]> git.proxmox.com Git - libgit2.git/commitdiff
New upstream version 1.3.0+dfsg.1
authorPirate Praveen <praveen@debian.org>
Fri, 10 Dec 2021 11:12:08 +0000 (16:42 +0530)
committerPirate Praveen <praveen@debian.org>
Fri, 10 Dec 2021 11:12:08 +0000 (16:42 +0530)
988 files changed:
.devcontainer/devcontainer.json [new file with mode: 0644]
.devcontainer/setup.sh [new file with mode: 0755]
.gitattributes
.github/workflows/codeql.yml [new file with mode: 0644]
.github/workflows/main.yml
.github/workflows/nightly.yml [new file with mode: 0644]
.gitignore
.vscode/launch.json [new file with mode: 0644]
.vscode/tasks.json [new file with mode: 0644]
CMakeLists.txt
COPYING
README.md
azure-pipelines.yml [deleted file]
azure-pipelines/bash.yml [deleted file]
azure-pipelines/build.sh [deleted file]
azure-pipelines/coverity.sh [deleted file]
azure-pipelines/coverity.yml [deleted file]
azure-pipelines/docker.yml [deleted file]
azure-pipelines/docker/bionic [deleted file]
azure-pipelines/docker/docurium [deleted file]
azure-pipelines/docker/entrypoint.sh [deleted file]
azure-pipelines/docker/focal [deleted file]
azure-pipelines/docker/xenial [deleted file]
azure-pipelines/getcontainer.sh [deleted file]
azure-pipelines/nightly.yml [deleted file]
azure-pipelines/setup-mingw.sh [deleted file]
azure-pipelines/setup-osx.sh [deleted file]
azure-pipelines/test.sh [deleted file]
ci/build.sh [new file with mode: 0755]
ci/coverity.sh [new file with mode: 0755]
ci/docker/bionic [new file with mode: 0644]
ci/docker/centos7 [new file with mode: 0644]
ci/docker/centos8 [new file with mode: 0644]
ci/docker/docurium [new file with mode: 0644]
ci/docker/focal [new file with mode: 0644]
ci/docker/xenial [new file with mode: 0644]
ci/getcontainer.sh [new file with mode: 0755]
ci/setup-mingw.sh [new file with mode: 0755]
ci/setup-osx.sh [new file with mode: 0755]
ci/test.sh [new file with mode: 0755]
cmake/FindLibSSH2.cmake [new file with mode: 0644]
cmake/Findfutimens.cmake [new file with mode: 0644]
cmake/SelectHTTPSBackend.cmake
cmake/SelectHashes.cmake
docs/changelog.md
docs/coding-style.md
docs/contributing.md
docs/release.md
docs/win32-longpaths.md [new file with mode: 0644]
examples/blame.c
examples/checkout.c
examples/common.h
examples/config.c
examples/general.c
examples/log.c
examples/rev-list.c
examples/rev-parse.c
examples/tag.c
fuzzers/commit_graph_fuzzer.c [new file with mode: 0644]
fuzzers/corpora/commit_graph/005682ce1cb5b20c20fccf4be5dbd47ca399e53e [new file with mode: 0644]
fuzzers/corpora/commit_graph/00574fc29fd1323e93d18d625cde80d3ea20e8cc [new file with mode: 0644]
fuzzers/corpora/commit_graph/00916ec21ddbd3c622bde6e4dc824250176b9e88 [new file with mode: 0644]
fuzzers/corpora/commit_graph/00b6dde4b8d5e68a5ec40d88c39134cf2f1f8bc3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/020f0e77e42d8b3810019050f4c5ceadd205b37c [new file with mode: 0644]
fuzzers/corpora/commit_graph/02739c05abc1715fac1ce995b532e482abc8d4dc [new file with mode: 0644]
fuzzers/corpora/commit_graph/02a276faa5dc8c7df5b82a57ab6cd195a13e4ae0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/02de15987d68a97db3d9fd964cfd785bcbd54d3a [new file with mode: 0644]
fuzzers/corpora/commit_graph/02e106f97a91b1d3aef4dd2d31368ae5077bd42b [new file with mode: 0644]
fuzzers/corpora/commit_graph/038555bcb4cc2daf764840f79ebce4023bdb7670 [new file with mode: 0644]
fuzzers/corpora/commit_graph/04c159a04b0732e04ac4c59ed3356860af8dffce [new file with mode: 0644]
fuzzers/corpora/commit_graph/0560ec993882ffbd8d46dcab0ed430089c4f2aa1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/059b3aab3fde6b4c9404aff83fed638596f594bb [new file with mode: 0644]
fuzzers/corpora/commit_graph/06168e726aa0260f520165be4ea0c88244831049 [new file with mode: 0644]
fuzzers/corpora/commit_graph/066d1ec700a526b97009cedd0305b6a47242faba [new file with mode: 0644]
fuzzers/corpora/commit_graph/086a5f8cbfa9f058b5c938a6eb724c9e4c5f84f3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/089313c698f3e351433e9a45af2ace1d85b9673e [new file with mode: 0644]
fuzzers/corpora/commit_graph/092eb973a771fa14cf0b567d65bd2c99130f543e [new file with mode: 0644]
fuzzers/corpora/commit_graph/094b8cd1aa3e40b1f9ff83680892d52e246df0f8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/0ce990c9c2ec121b8c78ba2bdf84679e04c0bdae [new file with mode: 0644]
fuzzers/corpora/commit_graph/0dd0770c34fcf6b1f13219450190616d344db021 [new file with mode: 0644]
fuzzers/corpora/commit_graph/0e2b2e6a32733b8a625bc7e812e2ea508d69a5e4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/0e8d0bd07c543d708aecaca377106492b7a74fa3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/0f0d16e1b8c8671dbe1074115c1d86aa9b359e7e [new file with mode: 0644]
fuzzers/corpora/commit_graph/102ef78036de5a30927e7f751377b05441c41a08 [new file with mode: 0644]
fuzzers/corpora/commit_graph/10494e7cc9cb8dff289c431d7560bcee0d1b14ed [new file with mode: 0644]
fuzzers/corpora/commit_graph/107b11d86381345f50aa19b8485477a870ff399f [new file with mode: 0644]
fuzzers/corpora/commit_graph/10bb37e18fb3c0897dabacf9c464b4d324007dc3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/10ee715f64b08549c3e8261204276694728eb841 [new file with mode: 0644]
fuzzers/corpora/commit_graph/123e4eeb7a731f48d06e336b4d29af717f8b6550 [new file with mode: 0644]
fuzzers/corpora/commit_graph/125a228afb923970e0a6d4412f7257ba998594a1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/130d96c16fba06dcbe7e2a661ab959a3274a4bd9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/131c5a2fec55cb0d63f7dc055d6fad5f3dc3c974 [new file with mode: 0644]
fuzzers/corpora/commit_graph/13e562d61acb3aa36260a819a00b07ff16450335 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1414e6e8ab6bad1b5c51fed807c514a9d6575e66 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1432d191846ae2d0e381813efcfacff2f1dba0e4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/14a84cdc6f8d432be4cd3d3eafce92ae385e472f [new file with mode: 0644]
fuzzers/corpora/commit_graph/14e3e735dba88791f2cadd6e0dc5d662a104a6d7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1574abb020203103ea629d677edd21c967fc0f4c [new file with mode: 0644]
fuzzers/corpora/commit_graph/169cc492ba94948a6206765436881a1a0c601780 [new file with mode: 0644]
fuzzers/corpora/commit_graph/16a2130c1d75129f3bae3bf8f2c2de41fb3533c0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/16ba602eadfc9a3f74c0845394eda0de42b61571 [new file with mode: 0644]
fuzzers/corpora/commit_graph/17555fb2dfc444d171ba686667d72e388bd6c041 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1a10450d99c1e53d9b7f97b8014cb7fc01906ef2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1af670b5515231fc04b2be9038ee30a7e066b09b [new file with mode: 0644]
fuzzers/corpora/commit_graph/1b72cfa68259e3f3b3802906902a0a29368f86b5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1c62ac5d632aa9e449a4335b675941107d8825ae [new file with mode: 0644]
fuzzers/corpora/commit_graph/1d95b5db2f802011b33d10212a66fbe40827dfd4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1e068537ce1211a325aab42ae1263a109131c9f9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/1e9c882c9d33304a5791ef6c98eee65e142bd7fd [new file with mode: 0644]
fuzzers/corpora/commit_graph/1f54935df929403a29e77591c97f767d94871aea [new file with mode: 0644]
fuzzers/corpora/commit_graph/206015659641771bb0d668728c2fdc4209e65dda [new file with mode: 0644]
fuzzers/corpora/commit_graph/2096493a2bcc2d15b7ae5bf3112fe49c39976ad8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/209b74e08abe8c787b7c5ba81e51cb69c57ecded [new file with mode: 0644]
fuzzers/corpora/commit_graph/21137876575fbca357fc0c96db1de73c6737e1ae [new file with mode: 0644]
fuzzers/corpora/commit_graph/2143d9db9802f076c72a71184cd9d0cb4581e9e7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/21a52a5282145407d951ac73c2ff27876783899d [new file with mode: 0644]
fuzzers/corpora/commit_graph/21d5c8c8ac3a09bcba5388c472df32795986a5cb [new file with mode: 0644]
fuzzers/corpora/commit_graph/22170d1110a1c18009b7feb21a470681f55e85fb [new file with mode: 0644]
fuzzers/corpora/commit_graph/22f55dff94785f24252d7a070f713840f59b0870 [new file with mode: 0644]
fuzzers/corpora/commit_graph/23d10ee9694e1c66bedc7060990f19a2ac3eaee3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2435430ca19502c3b0ec4987508d4a8fbdbc898c [new file with mode: 0644]
fuzzers/corpora/commit_graph/244d2ea0c5c3117000b599cfab37680ba8f04513 [new file with mode: 0644]
fuzzers/corpora/commit_graph/248bf94143d150da2459cfdca099c30c6daff00a [new file with mode: 0644]
fuzzers/corpora/commit_graph/25bc53498129bb3717671f00c355d2637a91c86a [new file with mode: 0644]
fuzzers/corpora/commit_graph/2614f60da2d7e291501397238366d27513bff773 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2651b3d5a8b4616b1faa81dabe27ab2712a27561 [new file with mode: 0644]
fuzzers/corpora/commit_graph/270257a2872b33dd13c4fd466cbc1ae67d613f9b [new file with mode: 0644]
fuzzers/corpora/commit_graph/2830c6244c74656f6c5649c8226953905a582a38 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2889a85c07c20551ff0b97fc640e3c91b33aa4a1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/295ce43fdd56def8948d1ba2bfa7fdf0c47b5318 [new file with mode: 0644]
fuzzers/corpora/commit_graph/296cbb94c4e68ab86972a174405308ee34d0c40f [new file with mode: 0644]
fuzzers/corpora/commit_graph/2975adf222cad108ec90d8225fd655e30e3bf253 [new file with mode: 0644]
fuzzers/corpora/commit_graph/29f5d27760c9254ab4db661a6cd0323dd11c34ca [new file with mode: 0644]
fuzzers/corpora/commit_graph/2a359fb09eaad968e57d353453908027645873d1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2a6b65a8d6c28febaa081d220a4433f8366d02bc [new file with mode: 0644]
fuzzers/corpora/commit_graph/2b14dcade4d0919b0a17830fe353738015f492a6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2b298a13abbd9829e965424a1486baa13d4166c4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2b44d8cd8e70e25172b4c740ebe38ef411c965b3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2b590c4e61fdfcf21c017b29440747a1894b1534 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2becb18a971ae30e1a8f6680982fd7305708caa0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2bf78b02099a1fe4ce50d065254e843ca55e280f [new file with mode: 0644]
fuzzers/corpora/commit_graph/2c1541ecd01aa7b9e99bccfe9804198b3e79f118 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2c6798057af5894c27631ff63e845fe1e4bdc9ee [new file with mode: 0644]
fuzzers/corpora/commit_graph/2cf7eb7fe489e5acd64df755e820c871784c2ba1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2d49ba35ca404baa0d593925f36a81ce53943c8d [new file with mode: 0644]
fuzzers/corpora/commit_graph/2d507d42ca43ffc2f3c8892826e1db74144ec096 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2e4da693e3e336d2b1a40311a7ccf94def035b6b [new file with mode: 0644]
fuzzers/corpora/commit_graph/2e71ff86128b5618f0f067c407a76ff645ae2019 [new file with mode: 0644]
fuzzers/corpora/commit_graph/2eb777c6d7e6ee9bd7a44e37372595043aad596b [new file with mode: 0644]
fuzzers/corpora/commit_graph/2ec3ebffba165b9dd49e755a9e77e23aed796628 [new file with mode: 0644]
fuzzers/corpora/commit_graph/302703e3b0d74219868aca39ee7593944c0b2400 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3048c6908dc3176707fa8bcb0196824e3358357a [new file with mode: 0644]
fuzzers/corpora/commit_graph/30616cb39d3ad6060324fada03709d611ad28d5c [new file with mode: 0644]
fuzzers/corpora/commit_graph/306beadd9b3135a00037323760eb5377c88a403e [new file with mode: 0644]
fuzzers/corpora/commit_graph/31464a6fbad023923a7e4700fc11564e811bcbd2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/317f4bcfecf066961ef1982d551cd14e63c9f008 [new file with mode: 0644]
fuzzers/corpora/commit_graph/31b2248faaabbec69a06098c8cb0f69c5d0aa208 [new file with mode: 0644]
fuzzers/corpora/commit_graph/31d1c3d1147385d58dbe6f82898a5523320fbcac [new file with mode: 0644]
fuzzers/corpora/commit_graph/32c9bc1616a78a230a3724abc02150db1cc40aa0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/331e2866416b091252f0299e98d32cfb29237029 [new file with mode: 0644]
fuzzers/corpora/commit_graph/331eb3876dd2f3f0bd51f380ac431d86d6e3bb5e [new file with mode: 0644]
fuzzers/corpora/commit_graph/346bd6eaeadeafcb840ff9441614b309330db63e [new file with mode: 0644]
fuzzers/corpora/commit_graph/349931f447981f21476481448576e805c093a25b [new file with mode: 0644]
fuzzers/corpora/commit_graph/34a2da1e9adaac1b4be1d40b1ece81fe00643d49 [new file with mode: 0644]
fuzzers/corpora/commit_graph/34bb8f475e7384a8a39618fd15fdc5fb1b12c1a1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/351a036c6eb95db9364706b861f7e75ad26194e8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/355452c1da8e7689d816d67cdde040b5df7eabd7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/35c157ad2b100b4f334cddcf3dea6ef2d85462be [new file with mode: 0644]
fuzzers/corpora/commit_graph/36a81a45eabfcf53e1ae0361aa234791e2fdb750 [new file with mode: 0644]
fuzzers/corpora/commit_graph/36ee20f6dbeb3a34e91eafbbe2e379f9ac6cfa43 [new file with mode: 0644]
fuzzers/corpora/commit_graph/377627c19bcac6adc880202048a9eac07b5417d4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/38747e7c8bec2f9c923739d50ba54ff88ba6503f [new file with mode: 0644]
fuzzers/corpora/commit_graph/3945843a6fab2ec71030f09b237c125b97cd3ea5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/396321d39b82ffaccbc64115117df7e822b0f515 [new file with mode: 0644]
fuzzers/corpora/commit_graph/396e78eb9b54e2cefb52cd76a22137c8abd6cbcf [new file with mode: 0644]
fuzzers/corpora/commit_graph/39c1ab66035adc104cd06a6d98b77668172d21af [new file with mode: 0644]
fuzzers/corpora/commit_graph/3a1078c35f5401ce09b5ba921fc348dde37530bb [new file with mode: 0644]
fuzzers/corpora/commit_graph/3aa3d8f40392d1c863d23799b8ec0aedc7191302 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3b08c505601271cb92345ec7f0ff0b28daf90a9c [new file with mode: 0644]
fuzzers/corpora/commit_graph/3b41702587be45f678b36823ad2f7e5002337dc4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3b69108cc919aba0248f9b864d4e71c5f6d1931e [new file with mode: 0644]
fuzzers/corpora/commit_graph/3b90507501bb3bcfe0094f9c92cc2869f1a7dda5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3bc7fe44c3a1464dd35a4d22b482f46cdeda0405 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3ce99994986efb6df3f3568423e0077b53c7ef78 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3d6cb3ba21181c9f0ab08b2608eab773f36773f2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3d8ec41450b943d5dea73fb1e393960b03d7c3b9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3e29e8baaac0f6c7e4cf3d5adca2ab3a2c491ac7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3e9469b3c68ba334671aacda7a7669b0e97b74d6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3eeda3bfa7abef69911c94520c009a08c49b9942 [new file with mode: 0644]
fuzzers/corpora/commit_graph/3f0f5021016451b57f673d0603cd9e4830c2198d [new file with mode: 0644]
fuzzers/corpora/commit_graph/3f46540fbd94bf0337c1d0d7437ec992a3568f09 [new file with mode: 0644]
fuzzers/corpora/commit_graph/402d9c25d5833d42630882ab5c57833266bef785 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4048bb3c26d67c345630ff9e86db551a3add6549 [new file with mode: 0644]
fuzzers/corpora/commit_graph/40792f23c1281842dab671e8b213fc408d1ec39f [new file with mode: 0644]
fuzzers/corpora/commit_graph/41cd0b5d9a9540947b7b1841a55e4c11bd4346a2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/41d86e5ea3df4a0de60d42aeb16e2a5599aedeae [new file with mode: 0644]
fuzzers/corpora/commit_graph/42b4e5430b2b1b17a361067fb9dd33ab74e52232 [new file with mode: 0644]
fuzzers/corpora/commit_graph/42ef1c9d234b90acaf1651d930fc52d5f8f158f2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4570c8ff26d7f31afe73b3d9a35a29bc1274d68a [new file with mode: 0644]
fuzzers/corpora/commit_graph/45cf4751a5929930a7c30ec10134434b9ee13c3d [new file with mode: 0644]
fuzzers/corpora/commit_graph/46e9d351dd5bb71f7d4d8f15b3fad312c781452e [new file with mode: 0644]
fuzzers/corpora/commit_graph/472421633b984556b96bc20f1fcf7a98c25736f3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/47f35b91699caee098cacdde0161ffab21bdfc57 [new file with mode: 0644]
fuzzers/corpora/commit_graph/48b9da327218f9409287687a43b7eead4789a588 [new file with mode: 0644]
fuzzers/corpora/commit_graph/48d14fca326d5d591d18d34c2821a457277819a2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/48f3a33e2a027f5735d0a333ec4acd5a2aa57118 [new file with mode: 0644]
fuzzers/corpora/commit_graph/49e0eee24eab094a9c62f6b37b6ba01f8aece4e4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4b45bcb707d2a0bc23b415e9bc3d7eb1f7f0e188 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4c428300fe4866fe81cff02ad4bc14b6848f7f73 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4d69c567df2e858c5f248b3fc8e4a9c04f02481c [new file with mode: 0644]
fuzzers/corpora/commit_graph/4d88b6c9b513d5db2e07313a39b43d112d3d4562 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4da73370cf854ef8bd08c7f79b92a187cdbff278 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4e4b2827351bbfd414b718052a8f950a9e3eb7ee [new file with mode: 0644]
fuzzers/corpora/commit_graph/4ed43f7d3c0305461edcbc86f62e0c6ad56df01e [new file with mode: 0644]
fuzzers/corpora/commit_graph/4f011529809e88205421fa8ce39dcc025293bcb8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4f1928b6376369ab6acf8a282284366cc3bf71ef [new file with mode: 0644]
fuzzers/corpora/commit_graph/4f669eca3416c44f0d003ef2720d03e697e2230e [new file with mode: 0644]
fuzzers/corpora/commit_graph/4f750f24ecb5080bea2845061cfd3ce4529d30ee [new file with mode: 0644]
fuzzers/corpora/commit_graph/4fab9bb2bacf562e65f4a8681c429e6ea92aaed7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/4fd757c7251c17413b3005fb38aee0fd029d89ec [new file with mode: 0644]
fuzzers/corpora/commit_graph/506092de91dcf93254cdd5ad9e02a953a38099ea [new file with mode: 0644]
fuzzers/corpora/commit_graph/50e934fb52d9bc5cd2a531adced1cad7f102a112 [new file with mode: 0644]
fuzzers/corpora/commit_graph/512e49a9e789656964988950009e6534907e6317 [new file with mode: 0644]
fuzzers/corpora/commit_graph/51404149f1ea30ee6959fafe81a52acabed97e9e [new file with mode: 0644]
fuzzers/corpora/commit_graph/5150f8a67399ee16178a2b08198cf91a90c0e53e [new file with mode: 0644]
fuzzers/corpora/commit_graph/51a1fd23dfe5a8062cd4601d235509247f3bc2dc [new file with mode: 0644]
fuzzers/corpora/commit_graph/51a963486f041a60c422f0dd6da3b69c52f12fb7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/51fbf57a2a35ec33164838fa254fe605a3c868e9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/53068b9f9cb54bb52d076e9602ccd55f169ef39a [new file with mode: 0644]
fuzzers/corpora/commit_graph/5314619e15fa5ee67df44481b8213a53786d39c5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/533f5f00275968129846522fe01e2819746272eb [new file with mode: 0644]
fuzzers/corpora/commit_graph/53a62799135c282435a17e032deda03eaf9daf0f [new file with mode: 0644]
fuzzers/corpora/commit_graph/53c9d5cd849977e523d92dd2d639e9b0e721be50 [new file with mode: 0644]
fuzzers/corpora/commit_graph/54767a0bb3b96d39f5b2004ce3f274465f1a927e [new file with mode: 0644]
fuzzers/corpora/commit_graph/548de37dbe6a3829b73d976996ec9838cf608554 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5522cefa54b798ea4aba8ef2a42ad248a7fb02ee [new file with mode: 0644]
fuzzers/corpora/commit_graph/554fab3eef5d8709f06d1d4319efe5c0c437421b [new file with mode: 0644]
fuzzers/corpora/commit_graph/567fe73919dae39b0bcb78b03d655643a71714a8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5717a281aa722ee4a32dfa1cc72fc5d6081f6755 [new file with mode: 0644]
fuzzers/corpora/commit_graph/577d814e0be43df9321c5b27119c398bd00a00c5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/58680611707c6188f9f067f8747b699cd2fe82d3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5915b7f91dd43ec37a4718061c90cbec2686b916 [new file with mode: 0644]
fuzzers/corpora/commit_graph/599516e368ff621dd06d8450837350f4e9558c38 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5a2d01d141e4d523e718c30e20cb07c3ad98f33d [new file with mode: 0644]
fuzzers/corpora/commit_graph/5a9803ef8cd88d1e8f1d6e5920b8afd170cafb11 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5ba93c9db0cff93f52b521d7420e43f6eda2784f [new file with mode: 0644]
fuzzers/corpora/commit_graph/5bf0ca772092e6fa34b6822f61a1b1c3d7f2c6e3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5cfbfb3e12b629dc9f74baf0a8741345ec288795 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5d8cc97b739c39820b761b6551d34dd647da6816 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5dcbb3e1c2fc9a191dd3f3443b86f6bc38c39e37 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5ec17d081aef9872f746e88ad8b03553719f9c36 [new file with mode: 0644]
fuzzers/corpora/commit_graph/5f88e3ba60c11be25c47a842763d8870d23cc7f2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6045e4d2bf85013c78a32e71b014ba3d4a4b7c61 [new file with mode: 0644]
fuzzers/corpora/commit_graph/615c7ba7ffbce955ffd964682e2a0f7ef3c767e4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6189f29cbbe88ac6cb32fdefecda1bd6194332a6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/627224cb8484c62992dcbc4cdebdbfa48a3c021a [new file with mode: 0644]
fuzzers/corpora/commit_graph/629fff0962d298a7283a3d1e1d1b940dfef9b315 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6322594cff2a99d0abb1139e6a43b06df76d539a [new file with mode: 0644]
fuzzers/corpora/commit_graph/63de5e8e042222d53bf05640c87da376aefb76cc [new file with mode: 0644]
fuzzers/corpora/commit_graph/647dbb1d05fe0fab685bfe126bd9ac3a12b6bccf [new file with mode: 0644]
fuzzers/corpora/commit_graph/647e5e265d8d1079784fc2a3da25f7ba58126acd [new file with mode: 0644]
fuzzers/corpora/commit_graph/653bd480dfd1e5f4bdca702aba3dfd8da0c204b7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/65485740a465377213c80fa68028727f281299fb [new file with mode: 0644]
fuzzers/corpora/commit_graph/6551f8c8c3028006d0cc4997943df8a86ee3f598 [new file with mode: 0644]
fuzzers/corpora/commit_graph/67799e79d33883510f85ae9705ab3932862128a2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/67b475481e5a21351b49789874adbc988aefd64c [new file with mode: 0644]
fuzzers/corpora/commit_graph/67e5a649967dee002d1c181e079748c404e29767 [new file with mode: 0644]
fuzzers/corpora/commit_graph/687424a4a31a66a78d1637c680c9c10746741007 [new file with mode: 0644]
fuzzers/corpora/commit_graph/68fa6dd52832657cb8dd7e1485d6fbafd4e93903 [new file with mode: 0644]
fuzzers/corpora/commit_graph/691696af1c042115f4d9f9b8e24f7b8c06ed189b [new file with mode: 0644]
fuzzers/corpora/commit_graph/6a80152f9b1afa3a3080bf3f6aa48e84c2e18497 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6af27e4cf4c7bcce128a5949ee27fc73ab2cc71e [new file with mode: 0644]
fuzzers/corpora/commit_graph/6afd8f82d5639b774de0dfd418ae85322f4168dd [new file with mode: 0644]
fuzzers/corpora/commit_graph/6c64a9e26e0e1480bb5e60b7044ca6ce17104a80 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6c850c17db130ca0152f7c75562fa191f7ef89de [new file with mode: 0644]
fuzzers/corpora/commit_graph/6c9afe4527371a2baf33c5e220e4ca21a3207f94 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6ce3d40b0225923a7f4123a919b1c5d70841fad7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6cfd064aa6197813eb18f38df967ae4cdba9c6da [new file with mode: 0644]
fuzzers/corpora/commit_graph/6e6675676c53bcddc870e06605d2432e3429f224 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6e6e82579b7abae2b43d90448d3f2ead4dfcba78 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6f13d23c75a562eddefafe85e208e602832294e2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/6fed59b0472927f5d2396d0ee4d7fd13579377ce [new file with mode: 0644]
fuzzers/corpora/commit_graph/71f7724196f9f8fcfe3ee0161a84893bb9c4ab11 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7335ecb1d41e713bf3909adf5802b90e22bc1581 [new file with mode: 0644]
fuzzers/corpora/commit_graph/73afaa73175f461e1d19d5138e055c1649926dfe [new file with mode: 0644]
fuzzers/corpora/commit_graph/73e2fcb45c4df90d19091056b235e7a317631a62 [new file with mode: 0644]
fuzzers/corpora/commit_graph/741cb2d5ae11b0a9e0608b58ec7284d75129a1f2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7431bb0097a9bb52e1ceaaa8674a13cd3486a387 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7455b805995d0c96ac12f8a1c1264caaffcfac1c [new file with mode: 0644]
fuzzers/corpora/commit_graph/74e39b8a82fc06f9ed8f83ea30545ddf6df66811 [new file with mode: 0644]
fuzzers/corpora/commit_graph/75d51e413d3e916560dc0c2ee5092d2f4972aec1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/75e068964ea6beb7310a154d763de74a70071f48 [new file with mode: 0644]
fuzzers/corpora/commit_graph/763bf498dd847bd2b4af7b611199619bd428bea6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/77064ae04581a3c6d2a77158ef1a0b1e60db414a [new file with mode: 0644]
fuzzers/corpora/commit_graph/783bb14d68021061f592601607f40fe232ad17c4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7862814cb684310b54ef920b35403515efaba13c [new file with mode: 0644]
fuzzers/corpora/commit_graph/791fd85b6ffb2429e9fa5ba29eebdce214ad88c7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/79396d4f6142a53e26e14aa6ccb4afb4fd8fc580 [new file with mode: 0644]
fuzzers/corpora/commit_graph/79661b8e529e2182d5c612faba9f26e32a122b78 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7969143acb3334bffac46c6dfd96362c81644191 [new file with mode: 0644]
fuzzers/corpora/commit_graph/79d84866dc8c067508c02516b65c0e48cf689b56 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7b61f8f4a96e309bbe64ed82637fc81492a9652f [new file with mode: 0644]
fuzzers/corpora/commit_graph/7b8123f973edfb0f3cab027c0cd6b8efc7b11d6b [new file with mode: 0644]
fuzzers/corpora/commit_graph/7b8dd3093efba07f7a4d3bab4b90b8f6e4f28bfb [new file with mode: 0644]
fuzzers/corpora/commit_graph/7cc771aab0f3be7730881a46d952ae0a06958201 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7d177f4207de78d50df2493a3bc07f2cd578b363 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7d2df075f3e73ea9809c31586c37ece0f568b7fa [new file with mode: 0644]
fuzzers/corpora/commit_graph/7d386e68e4c733a1fb11c0117f379fb4b9955fbb [new file with mode: 0644]
fuzzers/corpora/commit_graph/7e4260830352479d29310bd6e1022e19a68ffe76 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7e4dfdae52be18cf95555c2eb1f54af7f69c6dde [new file with mode: 0644]
fuzzers/corpora/commit_graph/7eafedf7e7f20e86ecdf9ba51febf8492bdbc1f1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/7ef1829a378d66b1dd70a767729127a0dc5edcae [new file with mode: 0644]
fuzzers/corpora/commit_graph/80b7d2b9d7e8c8fd7ae239b8d307b592f97ee000 [new file with mode: 0644]
fuzzers/corpora/commit_graph/810f577ff5c1af7807a26226af912687558158cd [new file with mode: 0644]
fuzzers/corpora/commit_graph/81603f1fe8d8e29005418d0fc9a9b33972366038 [new file with mode: 0644]
fuzzers/corpora/commit_graph/81c8b4d6884f954935fa4a8e828c4637db04b61a [new file with mode: 0644]
fuzzers/corpora/commit_graph/8226846e9b092561f85cc2956ab89d8cc1ae61e0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/825cfceea434e2392cce161356e3cb5f81ec2b3a [new file with mode: 0644]
fuzzers/corpora/commit_graph/82603febce83d95adf68b85cabf15d43ca0c4ee9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/827f0826cc4156e19b4c4938bec74e38de62fe9c [new file with mode: 0644]
fuzzers/corpora/commit_graph/8486397ff8d1156249676c19b419a7758ff53f9a [new file with mode: 0644]
fuzzers/corpora/commit_graph/84d99ee359bec1b8ee0f59e9bd96f1da062030b7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/84e629bc7416039f1feb81fa9168d7c1ee3141c2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/84e885752179076fb38739ca7bc4345716bee56a [new file with mode: 0644]
fuzzers/corpora/commit_graph/859ef05494c8070057810b5c20df00fc81f81cf5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/859fe592f33abc1d959c0e73ecd6cd4bffe23a97 [new file with mode: 0644]
fuzzers/corpora/commit_graph/860da5e8a468805b76a44b9ac99b4575be16ea15 [new file with mode: 0644]
fuzzers/corpora/commit_graph/865e415745cead02a826f058a5ee49099bdf9562 [new file with mode: 0644]
fuzzers/corpora/commit_graph/878bfce051a9c7462847d4e99b7e926dc821b7b8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/880492e4dc7259577c227bb4f075d7165e875c29 [new file with mode: 0644]
fuzzers/corpora/commit_graph/88b7de1bd1c96454a1350286d115c0ee368511f9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/896268e4a5775b7ce33923ac6daeb0810420c55b [new file with mode: 0644]
fuzzers/corpora/commit_graph/8978f8da89f9652878edabad164f5513ef508f27 [new file with mode: 0644]
fuzzers/corpora/commit_graph/89a6525b7db0e6ec211a484efd2880abef928d4e [new file with mode: 0644]
fuzzers/corpora/commit_graph/8ae86cba2bba6664fc5eb97be8e9777b8825d823 [new file with mode: 0644]
fuzzers/corpora/commit_graph/8b845fbd2aa14e4f83c4dbc8b4b0b54d06482acd [new file with mode: 0644]
fuzzers/corpora/commit_graph/8c4121e6ce5956cfa408b980f16d276f456374dc [new file with mode: 0644]
fuzzers/corpora/commit_graph/8cb6a5b8ab41e3d27668d5735b5c09ff1f2eab65 [new file with mode: 0644]
fuzzers/corpora/commit_graph/8d80a70ffd362a89b88663e27f11e8ab69b70c1b [new file with mode: 0644]
fuzzers/corpora/commit_graph/8db603c1720b3680047f831f2ea9862567a7cdc4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/8dd40b2d27c7dd4b986c35d87f826da287c09c4c [new file with mode: 0644]
fuzzers/corpora/commit_graph/8e9d6e6408e5f708a1924e8370e687e2c202a4c4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/8f2dff1a30ee28e5985cb9379828aea5658d5849 [new file with mode: 0644]
fuzzers/corpora/commit_graph/8f7d18cdd6e605b85784ada14571fd5e5a184f2a [new file with mode: 0644]
fuzzers/corpora/commit_graph/903ae52f0ac9af8348038b12f9259741b0de42f1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9119e331f59e9337d419739c324f49d1bd62c8bf [new file with mode: 0644]
fuzzers/corpora/commit_graph/91d54d03b0917314ea1d67a70690df9247dd08d2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/922da3b96725bfd0e3f6ce119f1e2249d53f9086 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9277561e0524cccba2f851970b0d88ec4f4d3f5e [new file with mode: 0644]
fuzzers/corpora/commit_graph/92a4d571804026b7bbe957396185e079e756b894 [new file with mode: 0644]
fuzzers/corpora/commit_graph/931224cc80168fd362a360d99bab813ed7bbf8ce [new file with mode: 0644]
fuzzers/corpora/commit_graph/936ea5dad3bf023c552aa0bbeea8f7f66a11612c [new file with mode: 0644]
fuzzers/corpora/commit_graph/93aa4e0b1864933dce0abc0df69fe3d261f117f2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/93d5b084965cf1b09085c4079a972e25207b3659 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9443fd3468bcc0bc3ff8dfe765225f045ab43d0a [new file with mode: 0644]
fuzzers/corpora/commit_graph/9624c26cefb5804b7906147d262e81ee4000b6d6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9890933a73f39208627bd36e2fe88a6d54343a74 [new file with mode: 0644]
fuzzers/corpora/commit_graph/989dad0448e79af10040d5080f74eba2b8a401ba [new file with mode: 0644]
fuzzers/corpora/commit_graph/98ed4808b4a8da66a91fcea1be63be6371a7c7ac [new file with mode: 0644]
fuzzers/corpora/commit_graph/9928e516b85e22fbad58d562d3b7e814d9ce812d [new file with mode: 0644]
fuzzers/corpora/commit_graph/994c7cc5599252b5628d89cd0ba4b5574d32bf00 [new file with mode: 0644]
fuzzers/corpora/commit_graph/99c8557c2a02ea030de42869af42c1f7c77114db [new file with mode: 0644]
fuzzers/corpora/commit_graph/9a14c867272f102b84efdba73662d318c3e51cfe [new file with mode: 0644]
fuzzers/corpora/commit_graph/9a6f158c176d4a1982d541be2bc27a8afba4ea57 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9aa4af603192823a2fdc53d95ed36896bc3309b2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9b40c2190123cec66af3b37212f6c567869efda3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9b6268c11d78c35db5164f1346905e602b6a49fe [new file with mode: 0644]
fuzzers/corpora/commit_graph/9c6883ba5cedb7d711b12733d66ef1a1156dd0af [new file with mode: 0644]
fuzzers/corpora/commit_graph/9c85c90f44b454ce0d52882c447f5ecb8d303634 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9cb7a2e89ec636da3fd41ecc49ebe25e5344e2c6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9d912dc5a3497e4b5b40b37202fc0ffbf5263666 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9dcbafe8c5345194ee0ce7eb4f6efaeb55543626 [new file with mode: 0644]
fuzzers/corpora/commit_graph/9f4b0f3d2d25e6405ba6093f24d0605327711573 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a047bf683239fa208dbac09424b105820ac23f43 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a1379dcd89ef5e73eabbfcc395113e3636e0ae09 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a38c7ef56adabd0916abac514154b1f362d40434 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a38ec6ad4a8466b4feb88e67b16524e8f3feac64 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a3fdea21020268b3b2409c1115d50697d9ae8f8c [new file with mode: 0644]
fuzzers/corpora/commit_graph/a45f1987a444b2c27e90fc1477e8b0815f75383f [new file with mode: 0644]
fuzzers/corpora/commit_graph/a4682958fb7029384c0a01a4a1356ac6f2f44fe1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a4de41561725960d6f48f210a4fb74d527f7b0c2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a5935f34435ecdd6587ad4f77b20d479d3387dbe [new file with mode: 0644]
fuzzers/corpora/commit_graph/a5b394beb2b1d463ad80924a8c8c70584bf5c629 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a62bc806f8c98ba7986243c2185a0548a8dd57ef [new file with mode: 0644]
fuzzers/corpora/commit_graph/a7013e97948893e0118c686c06e332cc611bea7e [new file with mode: 0644]
fuzzers/corpora/commit_graph/a74f5df8c7f25c37c15c0f74ed50019d17338225 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a7ab3559fb3da3f027e67091116253f3bdfd7828 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a845c8258a02022d447ea9249788b345f5504648 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a8d3e026e2393587eb170afb32e94ff0e1f8a8be [new file with mode: 0644]
fuzzers/corpora/commit_graph/a8d547e41ee21e163e65cf0a186d469dfa50ec19 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a8fa22521dd6813e595cc0a9586ee71fff305fe2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a9969442d585d9a53259c71c73b095701280eac5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/a99789d0ce2d7b937aaa8afa3cfc0f4ccd7be95f [new file with mode: 0644]
fuzzers/corpora/commit_graph/aaca30ee3ab38edfa2b061fcbcbca0c0ea657f15 [new file with mode: 0644]
fuzzers/corpora/commit_graph/aacdec3f05e98eb6eedddb9c6edb968e1a63c551 [new file with mode: 0644]
fuzzers/corpora/commit_graph/aadd85127241b94a41d02d9e9699e3e9773de1c9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ab8ad126702803d21dbafc85713bbee7f25f36e5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ac26f9afd599ff6f33396c2e02130654f3e2390c [new file with mode: 0644]
fuzzers/corpora/commit_graph/ac8b129e4756fda0c50c9dd0eb13e34c7b41ce8e [new file with mode: 0644]
fuzzers/corpora/commit_graph/aceaf3b72c2627dd3dd065974b854150681c093f [new file with mode: 0644]
fuzzers/corpora/commit_graph/ad1fcdc3bf806392e754a902eba9edd3b344c31f [new file with mode: 0644]
fuzzers/corpora/commit_graph/ad8c80e532482f9dfbfbb7c0d447f1f4e592bf72 [new file with mode: 0644]
fuzzers/corpora/commit_graph/add92b71bf897da2f71f691e6abcb6d02cb8e99f [new file with mode: 0644]
fuzzers/corpora/commit_graph/aeb8ccf6d82be9236c9e689e1580d043bd701eb0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/af1a827aedbf674fff2bdeb5589554eec62787ab [new file with mode: 0644]
fuzzers/corpora/commit_graph/afaab9a75414d231176ad4582b6f8d81b5dbedb3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/afc12c4ebed1f3ab962d7dcef110b5328b1e24c3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b0044f3744cf019658d668a33f8d1e53ef8bd6ce [new file with mode: 0644]
fuzzers/corpora/commit_graph/b06adc81a4e1cdcda3786970ca07ed9dee0b6401 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b139802a1cc90fd5b86cae044c221361892c688d [new file with mode: 0644]
fuzzers/corpora/commit_graph/b1b8f251542db01bdb01be3b6d5b117b07db1834 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b1b9af93f84ed6861b9c0ade39980e89ef828c8f [new file with mode: 0644]
fuzzers/corpora/commit_graph/b2eae68035cafd4077f6a4c3e4e961fdc1e8122b [new file with mode: 0644]
fuzzers/corpora/commit_graph/b32897a6aedaa8c5a6e656dd808bafabc4ee5608 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b376e4fc517297f92ac1713803ae3b60d5ebbe43 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b3fd100b139cfbffaad68aacf7d462861e9dca35 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b40808ca955faab4829811bced1cccb2ab58ea58 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b43daf9f87a514bce74af3e5a39284c69c4e7011 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b477da07f3e5796ff4a98c8a5bdb0e4a634954bf [new file with mode: 0644]
fuzzers/corpora/commit_graph/b4a2ef09cf59ca5ccf810a6f001cce710cc02f6b [new file with mode: 0644]
fuzzers/corpora/commit_graph/b4b75e588cb83430c502a34ec3dcfaf774a00359 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b4ce98acd2b288b6cfc00461e2e15e0f8004030c [new file with mode: 0644]
fuzzers/corpora/commit_graph/b75563f30f7e4fb369d2449b723ee8b282d03eff [new file with mode: 0644]
fuzzers/corpora/commit_graph/b7a0a820afa7057081de186728d0d887131d9314 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b7e880446146c735a3f820fb93969c8c172c2fb5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b833073d3006e7cbac03c494603a9b75e7b2a723 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b89459c1fb6fc918db4c81a32a75ee66217f9ab8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b8aab6c9b2c706f8df0ff695ff94969171f9c807 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b9751182a36acb79b77585e1e379857a530e95c8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/b9ddb239b5a2c1348d972ec70a08507c35ba4432 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ba8f573256a0fbb95c5626f399ebc3ef50bbd826 [new file with mode: 0644]
fuzzers/corpora/commit_graph/bc165749042d5425c5d6d4e29b17769a2315a80d [new file with mode: 0644]
fuzzers/corpora/commit_graph/bc910bd349319e1ed44d7c7266e3ac99cc29ecc6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/bc97b1d4f57eb7770bc3983e2d57c8c01b21d29e [new file with mode: 0644]
fuzzers/corpora/commit_graph/bd06f768e35ded4437cb88e2bc0ddd0bea3fa84c [new file with mode: 0644]
fuzzers/corpora/commit_graph/bd702faff9725a7a1957fd0f85cc52799f37b682 [new file with mode: 0644]
fuzzers/corpora/commit_graph/bee4464861e1cae3cfdd5fbcb340efbf02e8d8ca [new file with mode: 0644]
fuzzers/corpora/commit_graph/bf7ad994b098ec85d62683a16e067635e21a8af5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c054fc89ed72101dec861668ff1738ef85b728b9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c06752415ac037fefe5172dc7245cd7c49ca7fca [new file with mode: 0644]
fuzzers/corpora/commit_graph/c0c8b54354d172a0be751e3e9b80be961bb15ddb [new file with mode: 0644]
fuzzers/corpora/commit_graph/c0e7ca9b5b4d0e72d23d7dc9e9d1f2463a17a20d [new file with mode: 0644]
fuzzers/corpora/commit_graph/c13576a29c98bee02aa47f646f5f170f9b7d83f9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c14edf1d34f40b3cc74772c81ebe5d72172cc662 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c2789364cb35d111f08f924d0d7550ea9785c61e [new file with mode: 0644]
fuzzers/corpora/commit_graph/c2d8b07acb13e43a89b6c4afb3ecb9817dd4a8e9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c36ed796c1bf839668db8fc3475a2ffb32ad8ceb [new file with mode: 0644]
fuzzers/corpora/commit_graph/c41ec9dd94427423e4704721e7f21eae0c44ef20 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c42c544fa9dbb1264b39bf920b40985384db1d16 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c45ec3f594abc15de0a8cc3ad748ba23cb34ec64 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c49004d980961f288616a4eb9ebf68123fd68ffa [new file with mode: 0644]
fuzzers/corpora/commit_graph/c4c3c3c8df24adf505127627b3090116de78d9a6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c5c1921293af4a5953cb386092694042715fcfb3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c615caad21cd8a754fcb2008420234c5511c62b7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c6a9ee3f8fdc42566c4799db3912a83c8c438d7f [new file with mode: 0644]
fuzzers/corpora/commit_graph/c6b661e976282051285b913b3728383f36103ef8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c716ba47f810c238fe7bda1fbdc7b1ccc34e9848 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c85b2fa4421302e2fa333a9e33d59a882aa04f4f [new file with mode: 0644]
fuzzers/corpora/commit_graph/c871d135f2d3117b326688355bc0fa6f26d56cd6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c915b02265a27d185a8b028305f082ddb3ebd704 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c952d38b3e642db4795d7f954b85f4f6d2a041aa [new file with mode: 0644]
fuzzers/corpora/commit_graph/c98ee52065736c4172f6ee0c31977bf1b560d685 [new file with mode: 0644]
fuzzers/corpora/commit_graph/c99b183a2cd0dd8a4c1a141cc6eebb0311501fa5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ca0cd26baff2f2c0759e619800ebbe7314d2bb95 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ca3e0d745c35d7cceb0f6e3f8a709eb658b7e5a8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cac667320e99e93a796bb89842de4675735eb4a4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cb41b00e9db33a07e27b3ee05d3bbecaf853b963 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cbdbd3f320eee627097778f15b9fb2c1dc2bd15f [new file with mode: 0644]
fuzzers/corpora/commit_graph/cc7f114000c83abb2ab17f0deab6dcfc2acde7f5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cc9bb93a6b7a1362a15f04898845dbe1447ec382 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cce7355f826bbcf3955394596d358abc7df6fe6f [new file with mode: 0644]
fuzzers/corpora/commit_graph/cceff2878a558166fb5bf2a0354c1be31dcc4e21 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cd96909f3ded7aa54bb2ffd2f2f47f8acc6f99e2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/cee9f69d7d1a227833fba127a529ea2a10341da3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d064f27a3109afde629165432f78f389da73ff07 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d07e3094f02b0c0e3bab370684c2d8c5634224d5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d0ba3413d5706de17de64824d78233d48c6efbec [new file with mode: 0644]
fuzzers/corpora/commit_graph/d136511364a74973b009f2be9b021d4122f71a6c [new file with mode: 0644]
fuzzers/corpora/commit_graph/d1d215c40bcc8dd4ce02b0c0621e90b183b40b3e [new file with mode: 0644]
fuzzers/corpora/commit_graph/d1e35b137b2027b61def408f3f3c8cf9bcab274e [new file with mode: 0644]
fuzzers/corpora/commit_graph/d349d137e57fb1a60ab8babd20e2acedc7a9042e [new file with mode: 0644]
fuzzers/corpora/commit_graph/d3714ec4d3acc6262295b0fc99c6ba699f5bfe65 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d419df696512216074f1c6b17ea1dfc81c0e6e20 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d49ad4fdafac251ceec32481826228c1698360aa [new file with mode: 0644]
fuzzers/corpora/commit_graph/d4f85ba549c87ccaba59971a25da7e07b57c9f4e [new file with mode: 0644]
fuzzers/corpora/commit_graph/d51ade0715bcea7decee2a045934599a10c1b07a [new file with mode: 0644]
fuzzers/corpora/commit_graph/d5447fb72c97462a3f47c8b2d55deb0afaa225f8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d6611a91c29291872ed2932455cb15ddb3801323 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d676f5e7efd6de6f2e1773231479471d2bba7261 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d6a21eaa08a957d8f428192e193c2508fca2c218 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d778052a29539344a9e3144e262e68df9628ebde [new file with mode: 0644]
fuzzers/corpora/commit_graph/d884f6944adfff7cb41728062bf91cac5cdacfc9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d89aae18d8e320bbae55eaae6a0514d7e005a883 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d926fde818c63f7b34f38c9f018bc833bc0bf7e1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/d9d542d7c56774143cb6362e5a63739055469349 [new file with mode: 0644]
fuzzers/corpora/commit_graph/da99bc9ce5b831f132dfb2eb11b8537e5cccfcd4 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dabff2729fa69ab507fb00b7392aee1262056a29 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dac4f4b91e33847bcedf7c66ef6e4ad0181e8ad8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/db10ff6d01c7a66aa1823b9f99193590ddce99c6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dbbda2208fa688a5275dda0d304630db01ca081d [new file with mode: 0644]
fuzzers/corpora/commit_graph/dc47c5037be68a2747ff8a9fa450e1078a5ac5a5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dc760f136b123e38677aec72853e3365f08010fc [new file with mode: 0644]
fuzzers/corpora/commit_graph/dca41b901bf1612d4197e6a450366a00ac036ec3 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dca62f21fce50d1c8c51b82e0d7eeedc6746e652 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dcc7e6c444f95b10d634b1137413824e2cd68f62 [new file with mode: 0644]
fuzzers/corpora/commit_graph/dcf4b6addda69040f792c9b860ade2af0b77a14c [new file with mode: 0644]
fuzzers/corpora/commit_graph/dd6178166ac1eed82d132fea491bcda0d953227c [new file with mode: 0644]
fuzzers/corpora/commit_graph/ddbd5d3074323ccd7cd70bf5de5a2f30de977d99 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ddd8ec5632bf1b8153d03a4537d3d76517c497d5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/de7a56f36e10d7b9ff43160b1cea3e76b24386d1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/defa60aa46ea5a47c09b6962b4e4296ef1bcad92 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e0ae419425207832518d66c0ef35d11cbdc20361 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e0f519accbf15bc57a1bf1d7cc46d2a0b07a67f5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e128eff8ca7572d9bb0bfc84f64d79c52afc2c67 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e17fdc21ae03243bd1d31bb6301b4187cab6fe47 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e340ace35a2db7f89d6aa21cc1300766a74be4e1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e36dfc11bcaab1e42df13924a2d7da024684db2e [new file with mode: 0644]
fuzzers/corpora/commit_graph/e39e0c87ac5ce0b78c89ae2df84226baba666372 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e46b4666c6bfcd6f589ec3617a48cce9c968e833 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e57219555e11f9221d3166d5029ed2ad92300608 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e58ce590c2454e7ebe18e0a31a943b0b754fbd13 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e595f8fef5c8014cb0867978c6580301078ca0d9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e5b76398f60628e879328d7009b9fa89feea14cb [new file with mode: 0644]
fuzzers/corpora/commit_graph/e5cec0217eea93b18a59d76b0aed6b46b13fa6a9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e637b4e0b47d0d6cd870502e6a2d6a53bf917f73 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e7a6cb6e5a1552837fdbee9025fc48a9373f8564 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e7f57c48016e1180c9af95acd34470881f10bd06 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e8253c668bfe37df5c5ada3226860cee74fb33a2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e8f9981443c34ece02bca3c66130f3429d7b3375 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e91ed5416bbcd1b03803197b99c08f42c9869139 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e94201cfa88df7b198abd3abae9007a6780b52a7 [new file with mode: 0644]
fuzzers/corpora/commit_graph/e967bbd6a0d251ae62c9c38b784271d707f792c0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ea01737ceed783b3e0f66d9d0c409cb496c1d526 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ea40f7879a58d1e52a46404c761f76a949e14a31 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ea5ad04a54f95963baea1f47845847626e08dd55 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ea608a401f54b0ca70e42b897f0c8ce6efdbc0ef [new file with mode: 0644]
fuzzers/corpora/commit_graph/eb8700d6b3728e6e70c2a0fe504543771639f2b6 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ec1f271b04c322353865f4819153d46df7def873 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ee215536e7f0cfbd07b53dd65c5af9a604a01830 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ee4d4393d7d79b755f85ef5bf8f6e3d743bfa258 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ee8099331b2c392e7e036ffcd4a9b36ec2c2082d [new file with mode: 0644]
fuzzers/corpora/commit_graph/eede9da76db25513f8347f972e170102831de91a [new file with mode: 0644]
fuzzers/corpora/commit_graph/ef707cdeaa9548b6c820f769c1d8ad607b3c4514 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ef98609d8196dc158365dfcbbc47e3d1699c50c2 [new file with mode: 0644]
fuzzers/corpora/commit_graph/efa38b4269f978f3714b44b501831bea678244e0 [new file with mode: 0644]
fuzzers/corpora/commit_graph/efba428e29811d233720ccaaf41966a309312a29 [new file with mode: 0644]
fuzzers/corpora/commit_graph/efd514f056d8d83498b4724249c4623560e0390d [new file with mode: 0644]
fuzzers/corpora/commit_graph/f00e449ba67ef15e7f29df1e6948c28155d72baa [new file with mode: 0644]
fuzzers/corpora/commit_graph/f0a83929d588466051dced6eae0c387db307d646 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f0e53b72e5d69467e7c014474028ea734f4fcb26 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f186265b3f10f4383f4174e9fb74f0a0cdfa3fca [new file with mode: 0644]
fuzzers/corpora/commit_graph/f18932fcce5a9db5d6c8f59d622eabc25e255e12 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f2ea163bddb95d67597e2a747779ebf4651cb2a9 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f2f7d48a6d86143ecb4969808d634163576065b1 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f34a833faf2b0dcbae8aaad142c76c7c7e534e99 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f5c044ce01645c069334698fb8c4750e44835912 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f680112645c2502f0612e9d017bbb50cb28affbf [new file with mode: 0644]
fuzzers/corpora/commit_graph/f6b778d1b34415a7715905f54968c8b6eb057912 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f6ca6a62dc885c6b2a4b40c4aa1a7cb8118e30bb [new file with mode: 0644]
fuzzers/corpora/commit_graph/f733a8770c23fde182d2fef7e0d96e67244274d5 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f8529ddf17d4505c0932c3d40abe33cbfd8c6f22 [new file with mode: 0644]
fuzzers/corpora/commit_graph/f96f8419a3fc3719ae86d64e1147e7b7f66a2470 [new file with mode: 0644]
fuzzers/corpora/commit_graph/fae241a6c87af37781a3b49e534b7ddb6636eda8 [new file with mode: 0644]
fuzzers/corpora/commit_graph/faf8817a04b77c6a976ab0a3d1e905f79bb7f799 [new file with mode: 0644]
fuzzers/corpora/commit_graph/fb3e769019fb25d384d4be9d38e4cbce00a6adbc [new file with mode: 0644]
fuzzers/corpora/commit_graph/fb9b4b2a46f1c65076340a7bd03b076eb101b760 [new file with mode: 0644]
fuzzers/corpora/commit_graph/fca9b0a398832c9ba02cdc811f625b97d5beb18e [new file with mode: 0644]
fuzzers/corpora/commit_graph/fcb1b42c706e61245d5e86f708be777ae63f2772 [new file with mode: 0644]
fuzzers/corpora/commit_graph/fd6c463e7c30b0e51198c0d1ebbea25f20145e3f [new file with mode: 0644]
fuzzers/corpora/commit_graph/fdcbaa49097ad120c6d7709b29d5b65b8cf8e719 [new file with mode: 0644]
fuzzers/corpora/commit_graph/fe46775b28a2923b8770b44381552a8a1560d875 [new file with mode: 0644]
fuzzers/corpora/commit_graph/ff04441135ef3308fec2687cf688069c6df8aa31 [new file with mode: 0644]
git.git-authors
include/git2.h
include/git2/apply.h
include/git2/attr.h
include/git2/blame.h
include/git2/blob.h
include/git2/branch.h
include/git2/cert.h
include/git2/checkout.h
include/git2/clone.h
include/git2/commit.h
include/git2/common.h
include/git2/config.h
include/git2/deprecated.h
include/git2/diff.h
include/git2/email.h [new file with mode: 0644]
include/git2/errors.h
include/git2/filter.h
include/git2/graph.h
include/git2/index.h
include/git2/indexer.h
include/git2/notes.h
include/git2/odb.h
include/git2/oidarray.h
include/git2/patch.h
include/git2/rebase.h
include/git2/refs.h
include/git2/remote.h
include/git2/repository.h
include/git2/revparse.h
include/git2/stash.h
include/git2/status.h
include/git2/stdint.h
include/git2/submodule.h
include/git2/sys/commit_graph.h [new file with mode: 0644]
include/git2/sys/email.h [new file with mode: 0644]
include/git2/sys/filter.h
include/git2/sys/midx.h [new file with mode: 0644]
include/git2/sys/odb_backend.h
include/git2/sys/transport.h
include/git2/tag.h
include/git2/transport.h
include/git2/tree.h
include/git2/types.h
include/git2/version.h
include/git2/worktree.h
package.json
script/thread-sanitizer.supp [new file with mode: 0644]
script/valgrind.supp
src/CMakeLists.txt
src/alloc.c
src/allocators/failalloc.c [new file with mode: 0644]
src/allocators/failalloc.h [new file with mode: 0644]
src/allocators/stdalloc.c
src/allocators/win32_crtdbg.c [deleted file]
src/allocators/win32_crtdbg.h [deleted file]
src/allocators/win32_leakcheck.c [new file with mode: 0644]
src/allocators/win32_leakcheck.h [new file with mode: 0644]
src/annotated_commit.c
src/apply.c
src/array.h
src/attr.c
src/attr_file.c
src/attr_file.h
src/attrcache.c
src/attrcache.h
src/blame.c
src/blame_git.c
src/blob.c
src/branch.c
src/buf_text.c [deleted file]
src/buf_text.h [deleted file]
src/buffer.c
src/buffer.h
src/cache.c
src/cache.h
src/cc-compat.h
src/checkout.c
src/cherrypick.c
src/clone.c
src/commit.c
src/commit_graph.c [new file with mode: 0644]
src/commit_graph.h [new file with mode: 0644]
src/commit_list.c
src/commit_list.h
src/common.h
src/config.c
src/config_cache.c
src/config_file.c
src/config_parse.c
src/crlf.c
src/date.c
src/delta.c
src/describe.c
src/diff.c
src/diff_driver.c
src/diff_file.c
src/diff_generate.c
src/diff_print.c
src/diff_stats.c
src/diff_tform.c
src/diff_xdiff.c
src/diff_xdiff.h
src/email.c [new file with mode: 0644]
src/email.h [new file with mode: 0644]
src/errors.c
src/features.h.in
src/fetch.c
src/fetchhead.c
src/filebuf.c
src/filter.c
src/filter.h
src/futils.c
src/futils.h
src/global.c [deleted file]
src/global.h [deleted file]
src/graph.c
src/hash.c
src/hash.h
src/hash/sha1/collisiondetect.c
src/hash/sha1/common_crypto.c
src/hash/sha1/generic.h
src/hash/sha1/mbedtls.c
src/hash/sha1/openssl.c
src/hash/sha1/sha1dc/sha1.c
src/hash/sha1/win32.c
src/hashsig.c
src/ident.c
src/ignore.c
src/index.c
src/index.h
src/indexer.c
src/integer.h
src/iterator.c
src/iterator.h
src/khash.h
src/libgit2.c [new file with mode: 0644]
src/libgit2.h [new file with mode: 0644]
src/mailmap.c
src/map.h
src/merge.c
src/merge.h
src/merge_driver.c
src/merge_file.c
src/message.c
src/midx.c
src/midx.h
src/mwindow.c
src/mwindow.h
src/net.c
src/net.h
src/netops.c
src/netops.h
src/notes.c
src/object.c
src/odb.c
src/odb.h
src/odb_loose.c
src/odb_mempack.c
src/odb_pack.c
src/oid.c
src/oidarray.c
src/pack-objects.c
src/pack.c
src/pack.h
src/patch.c
src/patch_generate.c
src/patch_parse.c
src/path.c
src/path.h
src/pathspec.c
src/pool.c
src/posix.c
src/posix.h
src/reader.c
src/rebase.c
src/refdb.c
src/refdb_fs.c
src/reflog.c
src/refs.c
src/refs.h
src/refspec.c
src/remote.c
src/remote.h
src/repository.c
src/repository.h
src/reset.c
src/revert.c
src/revparse.c
src/revwalk.c
src/runtime.c [new file with mode: 0644]
src/runtime.h [new file with mode: 0644]
src/settings.c [deleted file]
src/settings.h [new file with mode: 0644]
src/signature.c
src/sortedcache.h
src/stash.c
src/status.c
src/strarray.c
src/streams/mbedtls.c
src/streams/mbedtls.h
src/streams/openssl.c
src/streams/openssl.h
src/streams/openssl_dynamic.c [new file with mode: 0644]
src/streams/openssl_dynamic.h [new file with mode: 0644]
src/streams/openssl_legacy.c [new file with mode: 0644]
src/streams/openssl_legacy.h [new file with mode: 0644]
src/streams/registry.c
src/streams/socket.c
src/streams/stransport.c
src/streams/tls.c
src/submodule.c
src/submodule.h
src/sysdir.c
src/tag.c
src/thread-utils.c [deleted file]
src/thread-utils.h [deleted file]
src/thread.c [new file with mode: 0644]
src/thread.h [new file with mode: 0644]
src/threadstate.c [new file with mode: 0644]
src/threadstate.h [new file with mode: 0644]
src/trace.c
src/trace.h
src/trailer.c
src/transaction.c
src/transport.c
src/transports/auth.c
src/transports/auth_negotiate.c
src/transports/auth_ntlm.c
src/transports/credential.c
src/transports/git.c
src/transports/http.c
src/transports/http.h
src/transports/httpclient.c
src/transports/httpclient.h
src/transports/local.c
src/transports/smart.c
src/transports/smart.h
src/transports/smart_protocol.c
src/transports/ssh.c
src/transports/winhttp.c
src/tree.c
src/tree.h
src/tsort.c
src/unix/map.c
src/unix/posix.h
src/unix/pthread.h
src/utf8.c [new file with mode: 0644]
src/utf8.h [new file with mode: 0644]
src/util.c
src/util.h
src/vector.c
src/vector.h
src/win32/findfile.c
src/win32/map.c
src/win32/msvc-compat.h
src/win32/path_w32.c
src/win32/path_w32.h
src/win32/posix.h
src/win32/posix_w32.c
src/win32/precompiled.h
src/win32/reparse.h
src/win32/thread.c
src/win32/thread.h
src/win32/w32_buffer.c
src/win32/w32_common.h
src/win32/w32_crtdbg_stacktrace.c [deleted file]
src/win32/w32_crtdbg_stacktrace.h [deleted file]
src/win32/w32_leakcheck.c [new file with mode: 0644]
src/win32/w32_leakcheck.h [new file with mode: 0644]
src/win32/w32_stack.c [deleted file]
src/win32/w32_stack.h [deleted file]
src/win32/w32_util.h
src/worktree.c
src/zstream.c
tests/CMakeLists.txt
tests/apply/apply_helpers.h
tests/apply/both.c
tests/apply/fromdiff.c
tests/apply/fromfile.c
tests/apply/partial.c
tests/attr/lookup.c
tests/attr/repo.c
tests/checkout/tree.c
tests/clar/fs.h
tests/clar/sandbox.h
tests/clar_libgit2.c
tests/clar_libgit2_trace.c
tests/clone/nonetwork.c
tests/config/include.c
tests/config/read.c
tests/core/buffer.c
tests/core/encoding.c
tests/core/integer.c [new file with mode: 0644]
tests/core/link.c
tests/core/opts.c
tests/core/path.c
tests/core/sha1.c
tests/core/sortedcache.c
tests/core/string.c
tests/core/strtol.c
tests/core/structinit.c
tests/core/useragent.c
tests/core/utf8.c [new file with mode: 0644]
tests/core/vector.c
tests/diff/format_email.c
tests/diff/patch.c
tests/diff/rename.c
tests/diff/workdir.c
tests/email/create.c [new file with mode: 0644]
tests/fetchhead/nonetwork.c
tests/filter/bare.c
tests/filter/crlf.c
tests/filter/custom.c
tests/filter/custom_helpers.c
tests/filter/stream.c
tests/filter/wildcard.c
tests/graph/commit_graph.c [new file with mode: 0644]
tests/graph/reachable_from_any.c [new file with mode: 0644]
tests/ignore/path.c
tests/ignore/status.c
tests/index/addall.c
tests/index/bypath.c
tests/iterator/workdir.c
tests/mailmap/parsing.c
tests/main.c
tests/merge/workdir/setup.c
tests/network/joinpath.c [deleted file]
tests/network/redirect.c [deleted file]
tests/network/refspecs.c
tests/network/remote/isvalidname.c
tests/network/remote/remotes.c
tests/network/url/joinpath.c [new file with mode: 0644]
tests/network/url/parse.c [new file with mode: 0644]
tests/network/url/pattern.c [new file with mode: 0644]
tests/network/url/redirect.c [new file with mode: 0644]
tests/network/urlparse.c [deleted file]
tests/object/blob/filter.c
tests/object/tag/list.c
tests/odb/foreach.c
tests/odb/sorting.c
tests/online/badssl.c
tests/online/clone.c
tests/online/customcert.c [new file with mode: 0644]
tests/online/fetch.c
tests/online/push_util.c
tests/online/push_util.h
tests/pack/filelimit.c
tests/pack/midx.c
tests/pack/threadsafety.c [new file with mode: 0644]
tests/path/core.c
tests/path/dotgit.c
tests/path/win32.c
tests/rebase/sign.c
tests/refs/basic.c
tests/refs/branches/name.c
tests/refs/branches/upstream.c
tests/refs/isvalidname.c
tests/refs/races.c
tests/refs/revparse.c
tests/refs/tags/name.c [new file with mode: 0644]
tests/remote/fetch.c [new file with mode: 0644]
tests/remote/httpproxy.c [new file with mode: 0644]
tests/repo/extensions.c [new file with mode: 0644]
tests/repo/getters.c
tests/repo/hashfile.c
tests/repo/init.c
tests/repo/open.c
tests/resources/certs/61f2ddb6.0 [new file with mode: 0644]
tests/resources/certs/db4f60b0.0 [new file with mode: 0644]
tests/resources/config/config21 [new file with mode: 0644]
tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb [new file with mode: 0644]
tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d [new file with mode: 0644]
tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c [new file with mode: 0644]
tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0 [new file with mode: 0644]
tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0 [new file with mode: 0644]
tests/resources/crlf.git/refs/heads/ident [new file with mode: 0644]
tests/resources/crlf.git/refs/heads/no-ident [new file with mode: 0644]
tests/resources/merge-recursive/.gitted/objects/info/commit-graph [new file with mode: 0644]
tests/resources/renames/.gitted/ORIG_HEAD [new file with mode: 0644]
tests/resources/renames/.gitted/index
tests/resources/renames/.gitted/logs/HEAD
tests/resources/renames/.gitted/objects/41/2a2eaf2c13103ea976b3b02c17abee7a358432 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/5a/71babaaac78a758b52576a60cea3c218c8b546 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/7e/7bfb88ba9bc65fd700fee1819cf1c317aafa56 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/bf/102db0c9c0c1513909a90e0611b5dddfc87c93 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/cc/980ffac5f1393696d4cd703ea9d2fde67dd367 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/db/98035f715427eef1f5e17f03e1801c05301e9e [new file with mode: 0644]
tests/resources/renames/.gitted/objects/eb/b3b7af1d25c8492d2f626826c92458b7cefd60 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/ed/2a95c4a6c295b9afcea50baff63ec544ccf600 [new file with mode: 0644]
tests/resources/renames/.gitted/objects/f6/7e2f70efe89665e829ea0d77c46965ad1307e4 [new file with mode: 0644]
tests/resources/renames/.gitted/refs/heads/break_rewrite [new file with mode: 0644]
tests/resources/revert-rename.git/HEAD [new file with mode: 0644]
tests/resources/revert-rename.git/config [new file with mode: 0644]
tests/resources/revert-rename.git/index [new file with mode: 0644]
tests/resources/revert-rename.git/objects/info/packs [new file with mode: 0644]
tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.idx [new file with mode: 0644]
tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.pack [new file with mode: 0644]
tests/resources/revert-rename.git/packed-refs [new file with mode: 0644]
tests/resources/revert-rename.git/refs/heads/master [new file with mode: 0644]
tests/resources/self-signed.pem [new file with mode: 0644]
tests/resources/testrepo.git/objects/info/commit-graph [new file with mode: 0644]
tests/revert/rename.c [new file with mode: 0644]
tests/revwalk/basic.c
tests/revwalk/mergebase.c
tests/status/worktree.c
tests/submodule/lookup.c
tests/threads/atomic.c [new file with mode: 0644]
tests/threads/basic.c
tests/threads/diff.c
tests/threads/thread_helpers.h
tests/threads/tlsdata.c [new file with mode: 0644]
tests/trace/windows/stacktrace.c
tests/win32/longpath.c
tests/worktree/merge.c
tests/worktree/worktree.c

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644 (file)
index 0000000..bc6344b
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "postCreateCommand": "bash .devcontainer/setup.sh"
+}
diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh
new file mode 100755 (executable)
index 0000000..c328bf3
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -e
+
+sudo apt-get update
+sudo apt-get -y --no-install-recommends install cmake
+
+mkdir build
+cd build
+cmake ..
\ No newline at end of file
index 176a458f94e0ea5272ce67c36bf30b6be9caf623..3d90b7d61f8a375dea839604da30c710cf7d0a2c 100644 (file)
@@ -1 +1,2 @@
 * text=auto
+tests/resources/** linguist-vendored
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644 (file)
index 0000000..38b4a04
--- /dev/null
@@ -0,0 +1,36 @@
+name: "CodeQL"
+
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: '21 3 * * 1'
+
+env:
+  docker-registry: docker.pkg.github.com
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Check out repository
+      uses: actions/checkout@v2
+      with:
+        fetch-depth: 0
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      with:
+        languages: 'cpp'
+
+    - name: Build
+      run: |
+        mkdir build
+        cd build
+        cmake .. -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+        cmake --build .        
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1
index 29507c8f03a61926fdf3ddd018f11a8ac0d1c467..572f025444a23879cbb2fe3cf4ab21a305c9ee33 100644 (file)
@@ -1,16 +1,17 @@
 # Continuous integration and pull request validation builds for the
-# master and maintenance branches.
+# main and maintenance branches.
 name: CI Build
 
 on:
   push:
-    branches: [ master, maint/* ]
+    branches: [ main, maint/* ]
   pull_request:
-    branches: [ master, maint/* ]
+    branches: [ main, maint/* ]
+  workflow_dispatch:
 
 env:
   docker-registry: docker.pkg.github.com
-  docker-config-path: azure-pipelines/docker
+  docker-config-path: source/ci/docker
 
 jobs:
   # Build the docker container images that we will use for our Linux
@@ -26,69 +27,99 @@ jobs:
     strategy:
       matrix:
         container:
-        - xenial
-        - bionic
-        - focal
-        - docurium
+        - name: xenial
+        - name: bionic
+        - name: focal
+        - name: docurium
+        - name: bionic-x86
+          dockerfile: bionic
+          base: multiarch/ubuntu-core:x86-bionic
+          qemu: true
+        - name: bionic-arm32
+          dockerfile: bionic
+          base: multiarch/ubuntu-core:armhf-bionic
+          qemu: true
+        - name: bionic-arm64
+          dockerfile: bionic
+          base: multiarch/ubuntu-core:arm64-bionic
+          qemu: true
+        - name: centos7
+        - name: centos8
     runs-on: ubuntu-latest
     steps:
     - name: Check out repository
       uses: actions/checkout@v2
       with:
+        path: source
         fetch-depth: 0
-      if: github.event_name == 'push'
+      if: github.event_name != 'pull_request'
+    - name: Setup QEMU
+      run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
+      if: matrix.container.qemu == true
     - name: Download existing container
-      run: azure-pipelines/getcontainer.sh ${{ env.docker-config-path }}/${{ matrix.container }}
+      run: |
+        "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.container.name }}" "${{ matrix.container.dockerfile }}"
       env:
         DOCKER_REGISTRY: ${{ env.docker-registry }}
         GITHUB_TOKEN: ${{ secrets.github_token }}
-      if: github.event_name == 'push'
+      working-directory: ${{ env.docker-config-path }}
+      if: github.event_name != 'pull_request'
     - name: Build and publish image
       run: |
-        docker build -t ${{ env.docker-registry-container-sha }} --build-arg BASE=${{ matrix.container.base }} -f ${{ matrix.container }} .
+        if [ "${{ matrix.container.base }}" != "" ]; then
+          BASE_ARG="--build-arg BASE=${{ matrix.container.base }}"
+        fi
+        docker build -t ${{ env.docker-registry-container-sha }} ${BASE_ARG} -f ${{ env.dockerfile }} .
+        docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }}
         docker push ${{ env.docker-registry-container-sha }}
+        docker push ${{ env.docker-registry-container-latest }}
       working-directory: ${{ env.docker-config-path }}
-      if: github.event_name == 'push' && env.docker-container-exists != 'true'
+      if: github.event_name != 'pull_request' && env.docker-container-exists != 'true'
 
   # Run our CI/CD builds.  We build a matrix with the various build targets
   # and their details.  Then we build either in a docker container (Linux)
   # or on the actual hosts (macOS, Windows).
   build:
     name: Build
-    needs: [build_containers]
+    needs: [ build_containers ]
     strategy:
       matrix:
         platform:
         - # Xenial, GCC, OpenSSL
-          image: xenial
+          container:
+            name: xenial
           env:
             CC: gcc
             CMAKE_GENERATOR: Ninja
-            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON
           os: ubuntu-latest
         - # Xenial, GCC, mbedTLS
-          image: xenial
+          container:
+            name: xenial
           env:
             CC: gcc
             CMAKE_GENERATOR: Ninja
             CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
           os: ubuntu-latest
         - # Xenial, Clang, OpenSSL
-          image: xenial
+          container:
+            name: xenial
           env:
             CC: clang
             CMAKE_GENERATOR: Ninja
             CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
           os: ubuntu-latest
         - # Xenial, Clang, mbedTLS
-          image: xenial
+          container:
+            name: xenial
           env:
             CC: clang
             CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
             CMAKE_GENERATOR: Ninja
           os: ubuntu-latest
         - # Focal, Clang 10, mbedTLS, MemorySanitizer
-          image: focal
+          container:
+            name: focal
           env:
             CC: clang-10
             CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
@@ -97,9 +128,11 @@ jobs:
             SKIP_SSH_TESTS: true
             SKIP_NEGOTIATE_TESTS: true
             ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+            UBSAN_OPTIONS: print_stacktrace=1
           os: ubuntu-latest
         - # Focal, Clang 10, OpenSSL, UndefinedBehaviorSanitizer
-          image: focal
+          container:
+            name: focal
           env:
             CC: clang-10
             CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
@@ -108,13 +141,27 @@ jobs:
             SKIP_SSH_TESTS: true
             SKIP_NEGOTIATE_TESTS: true
             ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+            UBSAN_OPTIONS: print_stacktrace=1
+          os: ubuntu-latest
+        - # Focal, Clang 10, OpenSSL, ThreadSanitizer
+          container:
+            name: focal
+          env:
+            CC: clang-10
+            CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer
+            CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+            CMAKE_GENERATOR: Ninja
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+            ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+            UBSAN_OPTIONS: print_stacktrace=1
+            TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1
           os: ubuntu-latest
         - # macOS
           os: macos-10.15
           env:
             CC: clang
             CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
-            CMAKE_GENERATOR: Ninja
             PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
             SKIP_SSH_TESTS: true
             SKIP_NEGOTIATE_TESTS: true
@@ -124,7 +171,7 @@ jobs:
           env:
             ARCH: amd64
             CMAKE_GENERATOR: Visual Studio 16 2019
-            CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
+            CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON
             SKIP_SSH_TESTS: true
             SKIP_NEGOTIATE_TESTS: true
         - # Windows x86 Visual Studio
@@ -132,7 +179,7 @@ jobs:
           env:
             ARCH: x86
             CMAKE_GENERATOR: Visual Studio 16 2019
-            CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
+            CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
             SKIP_SSH_TESTS: true
             SKIP_NEGOTIATE_TESTS: true
         - # Windows amd64 mingw
@@ -164,30 +211,37 @@ jobs:
     - name: Check out repository
       uses: actions/checkout@v2
       with:
+        path: source
         fetch-depth: 0
     - name: Set up build environment
-      run: azure-pipelines/setup-${{ matrix.platform.setup-script }}.sh
+      run: source/ci/setup-${{ matrix.platform.setup-script }}.sh
       shell: bash
       if: matrix.platform.setup-script != ''
+    - name: Setup QEMU
+      run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
+      if: matrix.platform.container.qemu == true
     - name: Download container
-      run: azure-pipelines/getcontainer.sh ${{ env.docker-config-path }}/${{ matrix.platform.image }}
+      run: |
+        "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}"
       env:
         DOCKER_REGISTRY: ${{ env.docker-registry }}
         GITHUB_TOKEN: ${{ secrets.github_token }}
-      if: matrix.platform.image != ''
+      working-directory: ${{ env.docker-config-path }}
+      if: matrix.platform.container.name != ''
     - name: Create container
-      run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ matrix.platform.image }} .
+      run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} .
       working-directory: ${{ env.docker-config-path }}
-      if: matrix.platform.image != '' && env.docker-container-exists != 'true'
+      if: matrix.platform.container.name != '' && env.docker-container-exists != 'true'
     - name: Build and test
       run: |
         export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}"
 
-        if [ -n "${{ matrix.platform.image }}" ]; then
+        if [ -n "${{ matrix.platform.container.name }}" ]; then
           docker run \
               --rm \
-              -v "$(pwd):/home/libgit2/source" \
-              -w /home/libgit2/source \
+              --user libgit2:libgit2 \
+              -v "$(pwd)/source:/home/libgit2/source" \
+              -w /home/libgit2 \
               -e ASAN_SYMBOLIZER_PATH \
               -e CC \
               -e CFLAGS \
@@ -197,19 +251,21 @@ jobs:
               -e PKG_CONFIG_PATH \
               -e SKIP_NEGOTIATE_TESTS \
               -e SKIP_SSH_TESTS \
+              -e TSAN_OPTIONS \
+              -e UBSAN_OPTIONS \
               ${{ env.docker-registry-container-sha }} \
-              /bin/bash -c "mkdir build && cd build && ../azure-pipelines/build.sh && ../azure-pipelines/test.sh"
+              /bin/bash -c "mkdir build && cd build && ../source/ci/build.sh && ../source/ci/test.sh"
         else
           mkdir build && cd build
-          ../azure-pipelines/build.sh
-          ../azure-pipelines/test.sh
+          ../source/ci/build.sh
+          ../source/ci/test.sh
         fi
       shell: bash
 
   # Generate documentation using docurium.  We'll upload the documentation
   # as a build artifact so that it can be reviewed as part of a pull
   # request or in a forked build.  For CI builds in the main repository's
-  # master branch, we'll push the gh-pages branch back up so that it is
+  # main branch, we'll push the gh-pages branch back up so that it is
   # published to our documentation site.
   documentation:
     name: Generate documentation
@@ -219,8 +275,10 @@ jobs:
     - name: Check out repository
       uses: actions/checkout@v2
       with:
+        path: source
         fetch-depth: 0
     - name: Generate documentation
+      working-directory: source
       run: |
         git config user.name 'Documentation Generation'
         git config user.email 'libgit2@users.noreply.github.com'
@@ -228,8 +286,8 @@ jobs:
         docker login https://${{ env.docker-registry }} -u ${{ github.actor }} -p ${{ github.token }}
         docker run \
             --rm \
-            -v "$(pwd):/home/libgit2/source" \
-            -w /home/libgit2/source \
+            -v "$(pwd):/home/libgit2" \
+            -w /home/libgit2 \
             ${{ env.docker-registry }}/${{ github.repository }}/docurium:latest \
             cm doc api.docurium
         git checkout gh-pages
@@ -238,7 +296,8 @@ jobs:
       name: Upload artifact
       with:
         name: api-documentation
-        path: api-documentation.zip
+        path: source/api-documentation.zip
     - name: Push documentation branch
+      working-directory: source
       run: git push origin gh-pages
-      if: github.event_name == 'push' && github.repository == 'libgit2/libgit2'
+      if: github.event_name != 'pull_request' && github.repository == 'libgit2/libgit2'
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644 (file)
index 0000000..47ebf46
--- /dev/null
@@ -0,0 +1,339 @@
+# Nightly build for the main branch across multiple targets.
+name: Nightly Build
+
+on:
+  workflow_dispatch:
+  schedule:
+  - cron: '15 1 * * *'
+
+env:
+  docker-registry: docker.pkg.github.com
+  docker-config-path: source/ci/docker
+
+jobs:
+  # Run our nightly builds.  We build a matrix with the various build
+  # targets and their details.  Then we build either in a docker container
+  # (Linux) or on the actual hosts (macOS, Windows).
+  build:
+    name: Build
+    strategy:
+      matrix:
+        platform:
+        - # Xenial, GCC, OpenSSL
+          container:
+            name: xenial
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+          os: ubuntu-latest
+        - # Xenial, GCC, mbedTLS
+          container:
+            name: xenial
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+          os: ubuntu-latest
+        - # Xenial, Clang, OpenSSL
+          container:
+            name: xenial
+          env:
+            CC: clang
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+          os: ubuntu-latest
+        - # Xenial, Clang, mbedTLS
+          container:
+            name: xenial
+          env:
+            CC: clang
+            CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            CMAKE_GENERATOR: Ninja
+          os: ubuntu-latest
+        - # Xenial, GCC, thread-free
+          container:
+            name: xenial
+          env:
+            CC: gcc
+            CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            CMAKE_GENERATOR: Ninja
+          os: ubuntu-latest
+        - # Xenial, Clang, OpenSSL (dynamically loaded)
+          container:
+            name: xenial
+          env:
+            CC: clang
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            CMAKE_GENERATOR: Ninja
+          os: ubuntu-latest
+        - # Focal, Clang 10, mbedTLS, MemorySanitizer
+          container:
+            name: focal
+          env:
+            CC: clang-10
+            CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
+            CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+            CMAKE_GENERATOR: Ninja
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+            ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+          os: ubuntu-latest
+        - # Focal, Clang 10, OpenSSL, UndefinedBehaviorSanitizer
+          container:
+            name: focal
+          env:
+            CC: clang-10
+            CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
+            CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+            CMAKE_GENERATOR: Ninja
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+            ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+          os: ubuntu-latest
+        - # Focal, Clang 10, OpenSSL, ThreadSanitizer
+          container:
+            name: focal
+          env:
+            CC: clang-10
+            CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer
+            CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+            CMAKE_GENERATOR: Ninja
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+            ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+            TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1
+          os: ubuntu-latest
+        - # Focal, Clang 10, mmap emulation (NO_MMAP)
+          container:
+            name: focal
+          env:
+            CC: clang-10
+            CFLAGS: -DNO_MMAP
+            CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local
+            CMAKE_GENERATOR: Ninja
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+          os: ubuntu-latest
+        - # CentOS 7
+          container:
+            name: centos7
+          env:
+            CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
+            SKIP_NEGOTIATE_TESTS: true
+          os: ubuntu-latest
+        - # CentOS 7, OpenSSL (dynamically loaded)
+          container:
+            name: centos7
+          env:
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
+            SKIP_NEGOTIATE_TESTS: true
+          os: ubuntu-latest
+        - # CentOS 8
+          container:
+            name: centos8
+          env:
+            CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
+            SKIP_NEGOTIATE_TESTS: true
+            SKIP_SSH_TESTS: true
+          os: ubuntu-latest
+        - # CentOS 8, OpenSSL (dynamically loaded)
+          container:
+            name: centos8
+          env:
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
+            SKIP_NEGOTIATE_TESTS: true
+            SKIP_SSH_TESTS: true
+          os: ubuntu-latest
+        - # macOS
+          os: macos-10.15
+          env:
+            CC: clang
+            CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
+            PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+          setup-script: osx
+        - # Windows amd64 Visual Studio
+          os: windows-2019
+          env:
+            ARCH: amd64
+            CMAKE_GENERATOR: Visual Studio 16 2019
+            CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+        - # Windows amd64 Visual Studio (NO_MMAP)
+          os: windows-2019
+          env:
+            ARCH: amd64
+            CMAKE_GENERATOR: Visual Studio 16 2019
+            CFLAGS: -DNO_MMAP
+            CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+        - # Windows x86 Visual Studio
+          os: windows-2019
+          env:
+            ARCH: x86
+            CMAKE_GENERATOR: Visual Studio 16 2019
+            CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+        - # Windows amd64 mingw
+          os: windows-2019
+          setup-script: mingw
+          env:
+            ARCH: amd64
+            CMAKE_GENERATOR: MinGW Makefiles
+            CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+            BUILD_TEMP: D:\Temp
+            BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+        - # Windows x86 mingw
+          os: windows-2019
+          setup-script: mingw
+          env:
+            ARCH: x86
+            CMAKE_GENERATOR: MinGW Makefiles
+            CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+            BUILD_TEMP: D:\Temp
+            BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+            SKIP_SSH_TESTS: true
+            SKIP_NEGOTIATE_TESTS: true
+        - # Bionic, GCC, OpenSSL (dynamically loaded)
+          container:
+            name: bionic
+            dockerfile: bionic
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            RUN_INVASIVE_TESTS: true
+          os: ubuntu-latest
+        - # Bionic, x86, Clang, OpenSSL
+          container:
+            name: bionic-x86
+            dockerfile: bionic
+            qemu: true
+          env:
+            CC: clang
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            RUN_INVASIVE_TESTS: true
+          os: ubuntu-latest
+        - # Bionic, x86, GCC, OpenSSL
+          container:
+            name: bionic-x86
+            dockerfile: bionic
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+            RUN_INVASIVE_TESTS: true
+          os: ubuntu-latest
+        - # Bionic, arm32, GCC, OpenSSL
+          container:
+            name: bionic-arm32
+            dockerfile: bionic
+            qemu: true
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON
+            RUN_INVASIVE_TESTS: true
+            SKIP_PROXY_TESTS: true
+          os: ubuntu-latest
+        - # Bionic, arm64, GCC, OpenSSL
+          container:
+            name: bionic-arm64
+            dockerfile: bionic
+            qemu: true
+          env:
+            CC: gcc
+            CMAKE_GENERATOR: Ninja
+            CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON
+            RUN_INVASIVE_TESTS: true
+            SKIP_PROXY_TESTS: true
+          os: ubuntu-latest
+      fail-fast: false
+    env: ${{ matrix.platform.env }}
+    runs-on: ${{ matrix.platform.os }}
+    steps:
+    - name: Check out repository
+      uses: actions/checkout@v2
+      with:
+        path: source
+        fetch-depth: 0
+    - name: Set up build environment
+      run: source/ci/setup-${{ matrix.platform.setup-script }}.sh
+      shell: bash
+      if: matrix.platform.setup-script != ''
+    - name: Setup QEMU
+      run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
+      if: matrix.platform.container.qemu == true
+    - name: Download container
+      run: |
+        "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}"
+      env:
+        DOCKER_REGISTRY: ${{ env.docker-registry }}
+        GITHUB_TOKEN: ${{ secrets.github_token }}
+      working-directory: ${{ env.docker-config-path }}
+      if: matrix.platform.container.name != ''
+    - name: Create container
+      run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} .
+      working-directory: ${{ env.docker-config-path }}
+      if: matrix.platform.container.name != '' && env.docker-container-exists != 'true'
+    - name: Build and test
+      run: |
+        export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}"
+
+        if [ -n "${{ matrix.platform.container.name }}" ]; then
+          docker run \
+              --rm \
+              --user libgit2:libgit2 \
+              -v "$(pwd)/source:/home/libgit2/source" \
+              -w /home/libgit2 \
+              -e ASAN_SYMBOLIZER_PATH \
+              -e CC \
+              -e CFLAGS \
+              -e CMAKE_GENERATOR \
+              -e CMAKE_OPTIONS \
+              -e GITTEST_NEGOTIATE_PASSWORD \
+              -e PKG_CONFIG_PATH \
+              -e SKIP_NEGOTIATE_TESTS \
+              -e SKIP_SSH_TESTS \
+              -e TSAN_OPTIONS \
+              ${{ env.docker-registry-container-sha }} \
+              /bin/bash -c "mkdir build && cd build && ../source/ci/build.sh && ../source/ci/test.sh"
+        else
+          mkdir build && cd build
+          ../source/ci/build.sh
+          ../source/ci/test.sh
+        fi
+      shell: bash
+
+  coverity:
+    name: Coverity
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check out repository
+      uses: actions/checkout@v2
+      with:
+        path: source
+        fetch-depth: 0
+    - name: Download container
+      run: |
+        "${{ github.workspace }}/source/ci/getcontainer.sh" xenial
+      env:
+        DOCKER_REGISTRY: ${{ env.docker-registry }}
+        GITHUB_TOKEN: ${{ secrets.github_token }}
+      working-directory: ${{ env.docker-config-path }}
+    - name: Run Coverity
+      run: source/ci/coverity.sh
+      env:
+        COVERITY_TOKEN: ${{ secrets.coverity_token }}
index b38b7e16ee4bb926a91685e7c79e5505eae34528..1b482f038affd6b3b7a79f32994c6910bbbac955 100644 (file)
@@ -1,7 +1,8 @@
-build/
+/build/
 .DS_Store
 *~
 .*.swp
-tags
+/tags
 CMakeSettings.json
 .vs
+.idea
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644 (file)
index 0000000..d47d93a
--- /dev/null
@@ -0,0 +1,27 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "(gdb) Launch",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${workspaceFolder}/build/libgit2_clar",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "${fileDirname}",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            "setupCommands": [
+                {
+                    "description": "Enable pretty-printing for gdb",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644 (file)
index 0000000..64142d3
--- /dev/null
@@ -0,0 +1,27 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+      {
+        "label": "Build",
+        "type": "shell",
+        "command": "cd build && cmake --build . --parallel",
+        "group": "build",
+        "presentation": {
+          "reveal": "always",
+          "panel": "new"
+        }
+      },
+      {
+        "label": "Run Tests",
+        "type": "shell",
+        "command": "build/libgit2_clar -v",
+        "group": "test",
+        "presentation": {
+          "reveal": "always",
+          "panel": "new"
+        }
+      }
+    ]
+  }
\ No newline at end of file
index b6f23cf6bf12acc19ded342c726c35140d75e514..3dccec3109a4889044af02a95f75cbb46b381954 100644 (file)
@@ -13,7 +13,7 @@
 
 CMAKE_MINIMUM_REQUIRED(VERSION 3.5.1)
 
-project(libgit2 VERSION "1.1.0" LANGUAGES C)
+project(libgit2 VERSION "1.3.0" LANGUAGES C)
 
 # Add find modules to the path
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${libgit2_SOURCE_DIR}/cmake/")
@@ -27,6 +27,7 @@ INCLUDE(AddCFlagIfSupported)
 INCLUDE(FindPkgLibraries)
 INCLUDE(FindThreads)
 INCLUDE(FindStatNsec)
+INCLUDE(Findfutimens)
 INCLUDE(GNUInstallDirs)
 INCLUDE(IdeSplitSources)
 INCLUDE(FeatureSummary)
@@ -49,8 +50,10 @@ OPTION(USE_GSSAPI                    "Link with libgssapi for SPNEGO auth"                   OFF)
 OPTION(USE_STANDALONE_FUZZERS          "Enable standalone fuzzers (compatible with gcc)"       OFF)
 OPTION(USE_LEAK_CHECKER                        "Run tests with leak checker"                           OFF)
 OPTION(DEBUG_POOL                      "Enable debug pool allocator"                           OFF)
+OPTION(DEBUG_STRICT_ALLOC              "Enable strict allocator behavior"                      OFF)
+OPTION(DEBUG_STRICT_OPEN               "Enable path validation in open"                        OFF)
 OPTION(ENABLE_WERROR                   "Enable compilation with -Werror"                       OFF)
-OPTION(USE_BUNDLED_ZLIB                "Use the bundled version of zlib"                       OFF)
+OPTION(USE_BUNDLED_ZLIB                "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL"                     OFF)
    SET(USE_HTTP_PARSER                 "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.")
 OPTION(DEPRECATE_HARD                  "Do not include deprecated functions in the library"    OFF)
    SET(REGEX_BACKEND                   "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.")
@@ -89,8 +92,8 @@ IF(WIN32)
 ENDIF()
 
 IF(MSVC)
-       # Enable MSVC CRTDBG memory leak reporting when in debug mode.
-       OPTION(MSVC_CRTDBG              "Enable CRTDBG memory leak reporting"                   OFF)
+       # Enable leak checking using the debugging C runtime.
+       OPTION(WIN32_LEAKCHECK          "Enable leak reporting via crtdbg"                      OFF)
 ENDIF()
 
 IF (DEPRECATE_HARD)
@@ -129,8 +132,8 @@ IF (MSVC)
                SET(CRT_FLAG_RELEASE "/MD")
        ENDIF()
 
-       IF (MSVC_CRTDBG)
-               SET(GIT_MSVC_CRTDBG 1)
+       IF (WIN32_LEAKCHECK)
+               SET(GIT_WIN32_LEAKCHECK 1)
                SET(CRT_FLAG_DEBUG "${CRT_FLAG_DEBUG}")
                SET(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} Dbghelp.lib")
        ENDIF()
@@ -231,6 +234,8 @@ ELSE ()
        enable_warnings(unused-const-variable)
        enable_warnings(unused-function)
        enable_warnings(int-conversion)
+       enable_warnings(c11-extensions)
+       enable_warnings(c99-c11-compat)
 
        # MinGW uses gcc, which expects POSIX formatting for printf, but
        # uses the Windows C library, which uses its own format specifiers.
diff --git a/COPYING b/COPYING
index c0f61fb9158945f7b41abfd640630c914b2eb8d9..6bb39b0c1d9a530ad92f036b4315f53363404189 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -420,7 +420,7 @@ The GNU C Library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
+
 The GNU C Library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
@@ -1019,3 +1019,111 @@ following restrictions are are met:
 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+----------------------------------------------------------------------
+
+Portions of the OpenSSL headers are included under the OpenSSL license:
+
+Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+All rights reserved.
+
+This package is an SSL implementation written
+by Eric Young (eay@cryptsoft.com).
+The implementation was written so as to conform with Netscapes SSL.
+
+This library is free for commercial and non-commercial use as long as
+the following conditions are aheared to.  The following conditions
+apply to all code found in this distribution, be it the RC4, RSA,
+lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+included with this distribution is covered by the same copyright terms
+except that the holder is Tim Hudson (tjh@cryptsoft.com).
+
+Copyright remains Eric Young's, and as such any Copyright notices in
+the code are not to be removed.
+If this package is used in a product, Eric Young should be given attribution
+as the author of the parts of the library used.
+This can be in the form of a textual message at program startup or
+in documentation (online or textual) provided with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   "This product includes cryptographic software written by
+    Eric Young (eay@cryptsoft.com)"
+   The word 'cryptographic' can be left out if the rouines from the library
+   being used are not cryptographic related :-).
+4. If you include any Windows specific code (or a derivative thereof) from
+   the apps directory (application code) you must include an acknowledgement:
+   "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The licence and distribution terms for any publically available version or
+derivative of this code cannot be changed.  i.e. this code cannot simply be
+copied and put under another distribution licence
+[including the GNU Public Licence.]
+
+====================================================================
+Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+3. All advertising materials mentioning features or use of this
+   software must display the following acknowledgment:
+   "This product includes software developed by the OpenSSL Project
+   for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+
+4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+   endorse or promote products derived from this software without
+   prior written permission. For written permission, please contact
+   openssl-core@openssl.org.
+
+5. Products derived from this software may not be called "OpenSSL"
+   nor may "OpenSSL" appear in their names without prior written
+   permission of the OpenSSL Project.
+
+6. Redistributions of any form whatsoever must retain the following
+   acknowledgment:
+   "This product includes software developed by the OpenSSL Project
+   for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+
+THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
index a91f16067ccb84e801fff371f1de4e829f59575c..0cbde525b5a3448d91625dfcc052bc750e69ace3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,10 +3,10 @@ libgit2 - the Git linkable library
 
 | Build Status | |
 | ------------ | - |
-| **master** branch CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=master)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=master)   |
-| **v1.0 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v1.0)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v1.0) |
-| **v0.28 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.28)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.28) |
-| **Nightly** builds | [![Azure Pipelines Build Status](https://libgit2.visualstudio.com/libgit2/_apis/build/status/nightly?branchName=master&label=Full+Build)](https://libgit2.visualstudio.com/libgit2/_build/latest?definitionId=9&branchName=master) [![Coverity Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/coverity?branchName=master&label=Coverity+Build)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=21?branchName=master) [![Coverity Scan Build Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) |
+| **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) |
+| **v1.2 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.2&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.2) |
+| **v1.1 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.1&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.1) |
+| **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) |
 
 `libgit2` is a portable, pure C implementation of the Git core methods
 provided as a linkable library with a solid API, allowing to build Git
@@ -33,6 +33,7 @@ Additionally, the example code has been released to the public domain (see the
 Table of Contents
 =================
 
+* [Using libgit2](#using-libgit2)
 * [Quick Start](#quick-start)
 * [Getting Help](#getting-help)
 * [What It Can Do](#what-it-can-do)
@@ -52,6 +53,28 @@ Table of Contents
 * [How Can I Contribute?](#how-can-i-contribute)
 * [License](#license)
 
+Using libgit2
+=============
+
+Most of these instructions assume that you're writing an application
+in C and want to use libgit2 directly.  If you're _not_ using C,
+and you're writing in a different language or platform like .NET,
+Node.js, or Ruby, then there is probably a
+"[language binding](#language-bindings)" that you can use to take care
+of the messy tasks of calling into native code.
+
+But if you _do_ want to use libgit2 directly - because you're building
+an application in C - then you may be able use an existing binary.
+There are packages for the
+[vcpkg](https://github.com/Microsoft/vcpkg) and
+[conan](https://conan.io/center/libgit2)
+package managers.  And libgit2 is available in 
+[Homebrew](https://formulae.brew.sh/formula/libgit2) and most Linux
+distributions.
+
+However, these versions _may_ be outdated and we recommend using the
+latest version if possible.  Thankfully libgit2 is not hard to compile.
+
 Quick Start
 ===========
 
@@ -81,7 +104,8 @@ Getting Help
 
 **Chat with us**
 
-- via IRC: join [#libgit2](https://webchat.freenode.net/#libgit2) on Freenode
+- via IRC: join [#libgit2](https://web.libera.chat/#libgit2) on
+  [libera](https://libera.chat).
 - via Slack: visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up,
   then join us in `#libgit2`
 
@@ -201,6 +225,8 @@ On most systems you can build the library using the following commands
 
 Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace.
 
+If you're not familiar with CMake, [a more detailed explanation](https://preshing.com/20170511/how-to-build-a-cmake-based-project/) may be helpful.
+
 Running Tests
 -------------
 
@@ -219,7 +245,7 @@ run the index tests:
     $ ./libgit2_clar -sindex
 
 To run a single test named `index::racy::diff`, which corresponds to the test
-function [`test_index_racy__diff`](https://github.com/libgit2/libgit2/blob/master/tests/index/racy.c#L23):
+function [`test_index_racy__diff`](https://github.com/libgit2/libgit2/blob/main/tests/index/racy.c#L23):
 
     $ ./libgit2_clar -sindex::racy::diff
 
@@ -229,7 +255,7 @@ applicable to your platform or is particularly expensive.
 
 **Note:** There should be _no_ failing tests when you build an unmodified
 source tree from a [release](https://github.com/libgit2/libgit2/releases),
-or from the [master branch](https://github.com/libgit2/libgit2/tree/master).
+or from the [main branch](https://github.com/libgit2/libgit2/tree/main).
 Please contact us or [open an issue](https://github.com/libgit2/libgit2/issues)
 if you see test failures.
 
@@ -332,6 +358,7 @@ Here are the bindings to libgit2 that are currently available:
     * dlibgit <https://github.com/s-ludwig/dlibgit>
 * Delphi
     * GitForDelphi <https://github.com/libgit2/GitForDelphi>
+    * libgit2-delphi <https://github.com/todaysoftware/libgit2-delphi>
 * Erlang
     * Geef <https://github.com/carlosmn/geef>
 * Go
@@ -344,6 +371,7 @@ Here are the bindings to libgit2 that are currently available:
     * hgit2 <https://github.com/jwiegley/gitlib>
 * Java
     * Jagged <https://github.com/ethomson/jagged>
+    * Git24j <https://github.com/git24j/git24j>
 * Javascript / WebAssembly ( browser and nodejs )
     * WASM-git <https://github.com/petersalomonsen/wasm-git>
 * Julia
@@ -369,6 +397,7 @@ Here are the bindings to libgit2 that are currently available:
 * Python
     * pygit2 <https://github.com/libgit2/pygit2>
 * R
+    * gert <https://docs.ropensci.org/gert>
     * git2r <https://github.com/ropensci/git2r>
 * Ruby
     * Rugged <https://github.com/libgit2/rugged>
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644 (file)
index f3690b8..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-resources:
-- repo: self
-
-trigger:
-- master
-- maint/*
-
-jobs:
-- job: linux_amd64_xenial_gcc_openssl
-  displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: azure-pipelines/docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
-       GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-
-- job: linux_amd64_xenial_gcc_mbedtls
-  displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: azure-pipelines/docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
-       GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-
-- job: linux_amd64_xenial_clang_openssl
-  displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: azure-pipelines/docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=clang
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
-       GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-
-- job: linux_amd64_xenial_clang_mbedtls
-  displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: azure-pipelines/docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=clang
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
-       GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-
-- job: macos
-  displayName: 'macOS (amd64; 10.15)'
-  pool:
-    vmImage: 'macOS-10.15'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
-    displayName: Setup
-  - template: azure-pipelines/bash.yml
-    parameters:
-      environmentVariables:
-        TMPDIR: $(Agent.TempDirectory)
-        PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
-        CMAKE_GENERATOR: Ninja
-        CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
-        SKIP_SSH_TESTS: true
-        GITTEST_NEGOTIATE_PASSWORD: ${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-
-- job: windows_vs_amd64
-  displayName: 'Windows (amd64; Visual Studio)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - template: azure-pipelines/bash.yml
-    parameters:
-      environmentVariables:
-        CMAKE_GENERATOR: Visual Studio 15 2017
-        CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
-        SKIP_SSH_TESTS: true
-        SKIP_NEGOTIATE_TESTS: true
-
-- job: windows_vs_x86
-  displayName: 'Windows (x86; Visual Studio)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - template: azure-pipelines/bash.yml
-    parameters:
-      environmentVariables:
-        CMAKE_GENERATOR: Visual Studio 15 2017
-        CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
-        SKIP_SSH_TESTS: true
-        SKIP_NEGOTIATE_TESTS: true
-
-- job: windows_mingw_amd64
-  displayName: 'Windows (amd64; MinGW)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
-    displayName: Setup
-    env:
-      TEMP: $(Agent.TempDirectory)
-      ARCH: amd64
-  - template: azure-pipelines/bash.yml
-    parameters:
-      environmentVariables:
-        BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
-        CMAKE_GENERATOR: MinGW Makefiles
-        CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
-        SKIP_SSH_TESTS: true
-        SKIP_NEGOTIATE_TESTS: true
-
-- job: windows_mingw_x86
-  displayName: 'Windows (x86; MinGW)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
-    displayName: Setup
-    workingDirectory: '$(Build.BinariesDirectory)'
-    env:
-      TEMP: $(Agent.TempDirectory)
-      ARCH: x86
-  - template: azure-pipelines/bash.yml
-    parameters:
-      environmentVariables:
-        BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
-        CMAKE_GENERATOR: MinGW Makefiles
-        CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
-        SKIP_SSH_TESTS: true
-        SKIP_NEGOTIATE_TESTS: true
diff --git a/azure-pipelines/bash.yml b/azure-pipelines/bash.yml
deleted file mode 100644 (file)
index 33a442b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# These are the steps used for building on machines with bash.
-steps:
-- bash: . '$(Build.SourcesDirectory)/azure-pipelines/build.sh'
-  displayName: Build
-  workingDirectory: '$(Build.BinariesDirectory)'
-  env: ${{ parameters.environmentVariables }}
-- bash: . '$(Build.SourcesDirectory)/azure-pipelines/test.sh'
-  displayName: Test
-  workingDirectory: '$(Build.BinariesDirectory)'
-  env: ${{ parameters.environmentVariables }}
-- task: PublishTestResults@2
-  displayName: Publish Test Results
-  condition: succeededOrFailed()
-  inputs:
-    testResultsFiles: 'results_*.xml'
-    searchFolder: '$(Build.BinariesDirectory)'
-    mergeTestResults: true
diff --git a/azure-pipelines/build.sh b/azure-pipelines/build.sh
deleted file mode 100755 (executable)
index c230e67..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env bash
-#
-# Environment variables:
-#
-# SOURCE_DIR: Set to the directory of the libgit2 source (optional)
-#     If not set, it will be derived relative to this script.
-
-set -e
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-BUILD_DIR=$(pwd)
-BUILD_PATH=${BUILD_PATH:=$PATH}
-CMAKE=$(which cmake)
-CMAKE_GENERATOR=${CMAKE_GENERATOR:-Unix Makefiles}
-
-if [[ "$(uname -s)" == MINGW* ]]; then
-       BUILD_PATH=$(cygpath "$BUILD_PATH")
-fi
-
-indent() { sed "s/^/    /"; }
-
-echo "Source directory: ${SOURCE_DIR}"
-echo "Build directory:  ${BUILD_DIR}"
-echo ""
-
-if [ "$(uname -s)" = "Darwin" ]; then
-       echo "macOS version:"
-       sw_vers | indent
-fi
-
-if [ -f "/etc/debian_version" ]; then
-       echo "Debian version:"
-       (source /etc/lsb-release && echo "${DISTRIB_DESCRIPTION}") | indent
-fi
-
-echo "Kernel version:"
-uname -a 2>&1 | indent
-
-echo "CMake version:"
-env PATH="${BUILD_PATH}" "${CMAKE}" --version 2>&1 | indent
-
-if test -n "${CC}"; then
-       echo "Compiler version:"
-       "${CC}" --version 2>&1 | indent
-fi
-echo "Environment:"
-if test -n "${CC}"; then
-       echo "CC=${CC}" | indent
-fi
-if test -n "${CFLAGS}"; then
-       echo "CFLAGS=${CFLAGS}" | indent
-fi
-echo ""
-
-echo "##############################################################################"
-echo "## Configuring build environment"
-echo "##############################################################################"
-
-echo cmake -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS} -S \"${SOURCE_DIR}\"
-env PATH="${BUILD_PATH}" "${CMAKE}" -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G "${CMAKE_GENERATOR}" ${CMAKE_OPTIONS} -S "${SOURCE_DIR}"
-
-echo ""
-echo "##############################################################################"
-echo "## Building libgit2"
-echo "##############################################################################"
-
-env PATH="${BUILD_PATH}" "${CMAKE}" --build .
diff --git a/azure-pipelines/coverity.sh b/azure-pipelines/coverity.sh
deleted file mode 100755 (executable)
index c68b6f8..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash -e
-
-if test -z "$COVERITY_TOKEN"
-then
-    echo "Need to set a coverity token"
-    exit 1
-fi
-
-case $(uname -m) in
-    i?86)
-        BITS=32;;
-    amd64|x86_64)
-        BITS=64;;
-    *)
-        echo "Unsupported arch '$(uname -m)'"
-        exit 1;;
-esac
-
-SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
-SOURCE_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")"/..)
-BUILD_DIR=${SOURCE_DIR}/coverity-build
-TOOL_DIR=${BUILD_DIR}/coverity-tools
-
-# Install coverity tools
-if ! test -d "$TOOL_DIR"
-then
-    mkdir -p "$TOOL_DIR"
-    curl --silent --show-error --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" |
-        tar -xzC "$TOOL_DIR"
-    ln -s "$(find "$TOOL_DIR" -type d -name 'cov-analysis*')" "$TOOL_DIR"/cov-analysis
-fi
-
-cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_DIR"/cov-analysis/config/
-
-# Build libgit2 with Coverity
-mkdir -p "$BUILD_DIR"
-cd "$BUILD_DIR"
-cmake "$SOURCE_DIR"
-COVERITY_UNSUPPORTED=1 \
-    "$TOOL_DIR/cov-analysis/bin/cov-build" --dir cov-int \
-    cmake --build .
-
-# Upload results
-tar -czf libgit2.tgz cov-int
-REVISION=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
-HTML="$(curl \
-    --silent --show-error \
-    --write-out "\n%{http_code}" \
-    --form token="$COVERITY_TOKEN" \
-    --form email=libgit2@gmail.com \
-    --form file=@libgit2.tgz \
-    --form version="$REVISION" \
-    --form description="libgit2 build" \
-    https://scan.coverity.com/builds?project=libgit2)"
-
-# Status code is the last line
-STATUS_CODE="$(echo "$HTML" | tail -n1)"
-if test "${STATUS_CODE}" != 200 && test "${STATUS_CODE}" != 201
-then
-    echo "Received error code ${STATUS_CODE} from Coverity"
-    exit 1
-fi
diff --git a/azure-pipelines/coverity.yml b/azure-pipelines/coverity.yml
deleted file mode 100644 (file)
index a8747db..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-resources:
-- repo: self
-
-jobs:
-- job: coverity
-  displayName: 'Coverity'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - script: |
-     cd $(Build.SourcesDirectory)/azure-pipelines/docker
-     docker build -t libgit2/xenial --build-arg BASE=ubuntu:xenial -f xenial .
-    displayName: 'Build Docker image'
-  - task: Docker@0
-    displayName: Analyze
-    inputs:
-      action: 'Run an image'
-      imageName: libgit2/xenial
-      volumes: |
-       $(Build.SourcesDirectory):/home/libgit2/source
-       $(Build.BinariesDirectory):/home/libgit2/build
-      envVars: |
-       COVERITY_TOKEN=$(COVERITY_TOKEN)
-      workDir: '/home/libgit2/build'
-      containerCommand: '/home/libgit2/source/azure-pipelines/coverity.sh'
-      detached: false
diff --git a/azure-pipelines/docker.yml b/azure-pipelines/docker.yml
deleted file mode 100644 (file)
index 0f08857..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-# These are the steps used in a container-based build in VSTS.
-steps:
-- ${{ if eq(parameters.qemu, 'true') }}:
-  - script: docker run --rm --privileged multiarch/qemu-user-static:register --reset
-    displayName: 'Register Docker QEMU'
-
-- task: cache@2
-  displayName: Cache Docker layers
-  inputs:
-    key: docker
-    path: /tmp/dockercache
-- script: |
-    if [ -f /tmp/dockercache/${{parameters.docker.image}}.tar ]; then docker load < /tmp/dockercache/${{parameters.docker.image}}.tar; fi
-  displayName: 'Load Docker cache'
-- script: |
-    cd $(Build.SourcesDirectory)/azure-pipelines/docker &&
-    docker build -t libgit2/${{parameters.docker.image}} --build-arg BASE=${{parameters.docker.base}} -f ${{parameters.docker.image}} . &&
-    if [ ! -d /tmp/dockercache ]; then mkdir /tmp/dockercache; fi &&
-    docker save libgit2/${{parameters.docker.image}} $(docker history -q libgit2/${{parameters.docker.image}} | grep -v '<missing>') > /tmp/dockercache/${{parameters.docker.image}}.tar
-  displayName: 'Build Docker image'
-- task: docker@0
-  displayName: Build
-  inputs:
-    action: 'Run an image'
-    imageName: libgit2/${{ parameters.docker.image }}
-    volumes: |
-     $(Build.SourcesDirectory):/home/libgit2/source
-     $(Build.BinariesDirectory):/home/libgit2/build
-    envVars: ${{ parameters.environmentVariables }}
-    workDir: '/home/libgit2/build'
-    containerCommand: '/home/libgit2/source/azure-pipelines/build.sh'
-    detached: false
-- task: docker@0
-  displayName: Test
-  inputs:
-    action: 'Run an image'
-    imageName: libgit2/${{ parameters.docker.image }}
-    volumes: |
-     $(Build.SourcesDirectory):/home/libgit2/source
-     $(Build.BinariesDirectory):/home/libgit2/build
-    envVars: ${{ parameters.environmentVariables }}
-    workDir: '/home/libgit2/build'
-    containerCommand: '/home/libgit2/source/azure-pipelines/test.sh'
-    detached: false
-- task: publishtestresults@2
-  displayName: Publish Test Results
-  condition: succeededOrFailed()
-  inputs:
-    testResultsFiles: 'results_*.xml'
-    searchFolder: '$(Build.BinariesDirectory)'
-    mergeTestResults: true
diff --git a/azure-pipelines/docker/bionic b/azure-pipelines/docker/bionic
deleted file mode 100644 (file)
index 5918584..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-FROM ubuntu:bionic AS apt
-RUN apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
-        clang \
-        cmake \
-        curl \
-        gcc \
-        git \
-        libcurl4-openssl-dev \
-        libpcre3-dev \
-        libssh2-1-dev \
-        libssl-dev \
-        libz-dev \
-        ninja-build \
-        openjdk-8-jre-headless \
-        openssh-server \
-        openssl \
-        pkgconf \
-        python \
-        sudo \
-        valgrind \
-        && \
-    rm -rf /var/lib/apt/lists/*
-
-FROM apt AS mbedtls
-RUN cd /tmp && \
-    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
-    tar -xz && \
-    cd mbedtls-2.16.2 && \
-    scripts/config.pl set MBEDTLS_MD4_C 1 && \
-    CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
-    ninja install && \
-    cd .. && \
-    rm -rf mbedtls-2.16.2
-
-FROM mbedtls AS configure
-COPY entrypoint.sh /usr/local/bin/entrypoint.sh
-RUN chmod a+x /usr/local/bin/entrypoint.sh
-RUN mkdir /var/run/sshd
-
-ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/azure-pipelines/docker/docurium b/azure-pipelines/docker/docurium
deleted file mode 100644 (file)
index 54a4202..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-FROM ubuntu:bionic
-RUN apt update && apt install -y cmake pkg-config ruby ruby-dev llvm libclang-dev libssl-dev python-pygments
-RUN gem install docurium
diff --git a/azure-pipelines/docker/entrypoint.sh b/azure-pipelines/docker/entrypoint.sh
deleted file mode 100644 (file)
index 8d96e3a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash -e
-useradd --shell /bin/bash libgit2
-chown --recursive libgit2:libgit2 /home/libgit2
-exec sudo --preserve-env --set-home --user=libgit2 "$@"
diff --git a/azure-pipelines/docker/focal b/azure-pipelines/docker/focal
deleted file mode 100644 (file)
index c75e85a..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-FROM ubuntu:focal AS apt
-RUN apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
-        bzip2 \
-        clang-10 \
-        cmake \
-        curl \
-        gcc-10 \
-        git \
-        krb5-user \
-        libcurl4-gnutls-dev \
-        libgcrypt20-dev \
-        libkrb5-dev \
-        libpcre3-dev \
-        libssl-dev \
-        libz-dev \
-        llvm-10 \
-        make \
-        ninja-build \
-        openjdk-8-jre-headless \
-        openssh-server \
-        openssl \
-        pkgconf \
-        python \
-        sudo \
-        valgrind \
-        && \
-    rm -rf /var/lib/apt/lists/* && \
-    mkdir /usr/local/msan
-
-FROM apt AS mbedtls
-RUN cd /tmp && \
-    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
-        tar -xz && \
-    cd mbedtls-2.16.2 && \
-    scripts/config.pl unset MBEDTLS_AESNI_C && \
-    scripts/config.pl set MBEDTLS_MD4_C 1 && \
-    mkdir build build-msan && \
-    cd build && \
-    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
-    ninja install && \
-    cd ../build-msan && \
-    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
-    ninja install && \
-    cd .. && \
-    rm -rf mbedtls-2.16.2
-
-FROM mbedtls AS libssh2
-RUN cd /tmp && \
-    curl --insecure --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \
-        tar -xz && \
-    cd libssh2-1.8.2 && \
-    mkdir build build-msan && \
-    cd build && \
-    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
-    ninja install && \
-    cd ../build-msan && \
-    CC=clang-10 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
-    ninja install && \
-    cd .. && \
-    rm -rf libssh2-1.8.2
-
-FROM libssh2 AS valgrind
-RUN cd /tmp && \
-    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
-        tar -xj && \
-    cd valgrind-3.15.0 && \
-    CC=clang-10 ./configure && \
-    make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \
-    make install && \
-    cd .. && \
-    rm -rf valgrind-3.15.0
-
-FROM valgrind AS configure
-COPY entrypoint.sh /usr/local/bin/entrypoint.sh
-RUN chmod a+x /usr/local/bin/entrypoint.sh
-RUN mkdir /var/run/sshd
-
-ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/azure-pipelines/docker/xenial b/azure-pipelines/docker/xenial
deleted file mode 100644 (file)
index 67867ed..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-FROM ubuntu:xenial AS apt
-RUN apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
-        bzip2 \
-        clang \
-        cmake \
-        curl \
-        gcc \
-        git \
-        krb5-user \
-        libcurl4-gnutls-dev \
-        libgcrypt20-dev \
-        libkrb5-dev \
-        libpcre3-dev \
-        libssl-dev \
-        libz-dev \
-        make \
-        ninja-build \
-        openjdk-8-jre-headless \
-        openssh-server \
-        openssl \
-        pkgconf \
-        python \
-        sudo \
-        valgrind \
-        && \
-    rm -rf /var/lib/apt/lists/*
-
-FROM apt AS mbedtls
-RUN cd /tmp && \
-    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
-    tar -xz && \
-    cd mbedtls-2.16.2 && \
-    scripts/config.pl set MBEDTLS_MD4_C 1 && \
-    CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
-    ninja install && \
-    cd .. && \
-    rm -rf mbedtls-2.16.2
-
-FROM mbedtls AS libssh2
-RUN cd /tmp && \
-    curl --insecure --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \
-    tar -xz && \
-    cd libssh2-1.8.2 && \
-    CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \
-    ninja install && \
-    cd .. && \
-    rm -rf libssh2-1.8.2
-
-FROM libssh2 AS valgrind
-RUN cd /tmp && \
-    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
-    tar -xj && \
-    cd valgrind-3.15.0 && \
-    ./configure && \
-    make && \
-    make install && \
-    cd .. && \
-    rm -rf valgrind-3.15.0
-
-FROM valgrind AS configure
-COPY entrypoint.sh /usr/local/bin/entrypoint.sh
-RUN chmod a+x /usr/local/bin/entrypoint.sh
-RUN mkdir /var/run/sshd
-
-ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/azure-pipelines/getcontainer.sh b/azure-pipelines/getcontainer.sh
deleted file mode 100755 (executable)
index bc93f49..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/bash
-
-set -e
-
-DOCKERFILE_PATH=$1
-
-if [ "${DOCKERFILE_PATH}" = "" ]; then
-       echo "usage: $0 dockerfile"
-       exit 1
-fi
-
-if [ "${DOCKER_REGISTRY}" = "" ]; then
-       echo "DOCKER_REGISTRY environment variable is unset."
-       echo "Not running inside GitHub Actions or misconfigured?"
-       exit 1
-fi
-
-DOCKER_CONTAINER="${GITHUB_REPOSITORY}/$(basename ${DOCKERFILE_PATH})"
-DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}"
-
-echo "::set-env name=docker-container::${DOCKER_CONTAINER}"
-echo "::set-env name=docker-registry-container::${DOCKER_REGISTRY_CONTAINER}"
-
-# Identify the last git commit that touched the Dockerfiles
-# Use this as a hash to identify the resulting docker containers
-DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}")
-echo "::set-env name=docker-sha::${DOCKER_SHA}"
-
-DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}"
-
-echo "::set-env name=docker-registry-container-sha::${DOCKER_REGISTRY_CONTAINER_SHA}"
-echo "::set-env name=docker-registry-container-latest::${DOCKER_REGISTRY_CONTAINER}:latest"
-
-exists="true"
-docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false"
-
-if [ "${exists}" != "false" ]; then
-       docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false"
-fi
-
-if [ "${exists}" = "true" ]; then
-       echo "::set-env name=docker-container-exists::true"
-else
-       echo "::set-env name=docker-container-exists::false"
-fi
diff --git a/azure-pipelines/nightly.yml b/azure-pipelines/nightly.yml
deleted file mode 100644 (file)
index a75a9cc..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-resources:
-- repo: self
-
-jobs:
-- job: linux_amd64_xenial_gcc_openssl
-  displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: linux_amd64_xenial_gcc_mbedtls
-  displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: linux_amd64_xenial_clang_openssl
-  displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=clang
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: linux_amd64_xenial_clang_mbedtls
-  displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      docker:
-        image: xenial
-        base: ubuntu:xenial
-      environmentVariables: |
-       CC=clang
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: macos
-  displayName: 'macOS (amd64; 10.15)'
-  pool:
-    vmImage: 'macOS-10.15'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
-    displayName: Setup
-  - template: bash.yml
-    parameters:
-      environmentVariables:
-        TMPDIR: $(Agent.TempDirectory)
-        PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
-        CMAKE_GENERATOR: Ninja
-        CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
-        RUN_INVASIVE_TESTS: true
-        SKIP_SSH_TESTS: true
-
-- job: windows_vs_amd64
-  displayName: 'Windows (amd64; Visual Studio)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - template: bash.yml
-    parameters:
-      environmentVariables:
-        CMAKE_GENERATOR: Visual Studio 15 2017
-        CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
-        RUN_INVASIVE_TESTS: true
-        SKIP_SSH_TESTS: true
-
-- job: windows_vs_x86
-  displayName: 'Windows (x86; Visual Studio)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - template: bash.yml
-    parameters:
-      environmentVariables:
-        CMAKE_GENERATOR: Visual Studio 15 2017
-        CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS
-        RUN_INVASIVE_TESTS: true
-        SKIP_SSH_TESTS: true
-
-- job: windows_mingw_amd64
-  displayName: 'Windows (amd64; MinGW)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
-    displayName: Setup
-    env:
-      TEMP: $(Agent.TempDirectory)
-      ARCH: amd64
-  - template: bash.yml
-    parameters:
-      environmentVariables:
-        BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
-        CMAKE_GENERATOR: MinGW Makefiles
-        CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
-        RUN_INVASIVE_TESTS: true
-        SKIP_SSH_TESTS: true
-
-- job: windows_mingw_x86
-  displayName: 'Windows (x86; MinGW)'
-  pool:
-    vmImage: 'vs2017-win2016'
-  steps:
-  - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
-    displayName: Setup
-    workingDirectory: '$(Build.BinariesDirectory)'
-    env:
-      TEMP: $(Agent.TempDirectory)
-      ARCH: x86
-  - template: bash.yml
-    parameters:
-      environmentVariables:
-        BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
-        CMAKE_GENERATOR: MinGW Makefiles
-        CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
-        RUN_INVASIVE_TESTS: true
-        SKIP_SSH_TESTS: true
-
-- job: linux_x86_bionic_gcc_openssl
-  displayName: 'Linux (x86; Bionic; GCC; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      qemu: 'true'
-      docker:
-        image: bionic
-        base: multiarch/ubuntu-core:x86-bionic
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: linux_x86_bionic_clang_openssl
-  displayName: 'Linux (x86; Bionic; Clang; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      qemu: 'true'
-      docker:
-        image: bionic
-        base: multiarch/ubuntu-core:x86-bionic
-      environmentVariables: |
-       CC=clang
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
-       RUN_INVASIVE_TESTS=true
-
-- job: linux_arm32_bionic_gcc_openssl
-  displayName: 'Linux (arm32; Bionic; GCC; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      qemu: 'true'
-      docker:
-        image: bionic
-        base: multiarch/ubuntu-core:armhf-bionic
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
-       RUN_INVASIVE_TESTS=true
-       SKIP_PROXY_TESTS=true
-
-- job: linux_arm64_bionic_gcc_openssl
-  displayName: 'Linux (arm64; Bionic; GCC; OpenSSL)'
-  pool:
-    vmImage: 'ubuntu-18.04'
-  steps:
-  - template: docker.yml
-    parameters:
-      qemu: 'true'
-      docker:
-        image: bionic
-        base: multiarch/ubuntu-core:arm64-bionic
-      environmentVariables: |
-       CC=gcc
-       CMAKE_GENERATOR=Ninja
-       CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
-       RUN_INVASIVE_TESTS=true
-       SKIP_PROXY_TESTS=true
diff --git a/azure-pipelines/setup-mingw.sh b/azure-pipelines/setup-mingw.sh
deleted file mode 100755 (executable)
index d500da0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh -e
-
-echo "##############################################################################"
-echo "## Downloading mingw"
-echo "##############################################################################"
-
-BUILD_TEMP=${BUILD_TEMP:=$TEMP}
-BUILD_TEMP=$(cygpath $BUILD_TEMP)
-
-case "$ARCH" in
-       amd64)
-               MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-x86_64-8.1.0-release-win32-seh-rt_v6-rev0.zip";;
-       x86)
-               MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";;
-esac
-
-if [ -z "$MINGW_URI" ]; then
-       echo "No URL"
-       exit 1
-fi
-
-mkdir -p "$BUILD_TEMP"
-
-curl -s -L "$MINGW_URI" -o "$BUILD_TEMP"/mingw-"$ARCH".zip
-unzip -q "$BUILD_TEMP"/mingw-"$ARCH".zip -d "$BUILD_TEMP"
diff --git a/azure-pipelines/setup-osx.sh b/azure-pipelines/setup-osx.sh
deleted file mode 100755 (executable)
index 2e630ee..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-set -x
-
-brew update
-brew install pkgconfig zlib curl openssl libssh2 ninja
-
-ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib
diff --git a/azure-pipelines/test.sh b/azure-pipelines/test.sh
deleted file mode 100755 (executable)
index 2b43ba1..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-if [ -n "$SKIP_TESTS" ]; then
-       exit 0
-fi
-
-# Windows doesn't run the NTLM tests properly (yet)
-if [[ "$(uname -s)" == MINGW* ]]; then
-        SKIP_NTLM_TESTS=1
-fi
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-BUILD_DIR=$(pwd)
-TMPDIR=${TMPDIR:-/tmp}
-USER=${USER:-$(whoami)}
-
-SUCCESS=1
-
-cleanup() {
-       echo "Cleaning up..."
-
-       if [ ! -z "$GITDAEMON_PID" ]; then
-               echo "Stopping git daemon..."
-               kill $GITDAEMON_PID
-       fi
-
-       if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then
-               echo "Stopping SSH..."
-               kill $(cat "${SSHD_DIR}/pid")
-       fi
-
-       echo "Done."
-}
-
-run_test() {
-       if [[ "$GITTEST_FLAKY_RETRY" > 0 ]]; then
-               ATTEMPTS_REMAIN=$GITTEST_FLAKY_RETRY
-       else
-               ATTEMPTS_REMAIN=1
-       fi
-
-       FAILED=0
-       while [[ "$ATTEMPTS_REMAIN" > 0 ]]; do
-               if [ "$FAILED" -eq 1 ]; then
-                       echo ""
-                       echo "Re-running flaky ${1} tests..."
-                       echo ""
-               fi
-
-               RETURN_CODE=0
-
-               CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" ctest -V -R "^${1}$" || RETURN_CODE=$? && true
-
-               if [ "$RETURN_CODE" -eq 0 ]; then
-                       FAILED=0
-                       break
-               fi
-
-               echo "Test exited with code: $RETURN_CODE"
-               ATTEMPTS_REMAIN="$(($ATTEMPTS_REMAIN-1))"
-               FAILED=1
-       done
-
-       if [ "$FAILED" -ne 0 ]; then
-               SUCCESS=0
-       fi
-}
-
-# Configure the test environment; run them early so that we're certain
-# that they're started by the time we need them.
-
-echo "##############################################################################"
-echo "## Configuring test environment"
-echo "##############################################################################"
-
-if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
-       echo "Starting git daemon..."
-       GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
-       git init --bare "${GITDAEMON_DIR}/test.git"
-       git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
-       GITDAEMON_PID=$!
-       disown $GITDAEMON_PID
-fi
-
-if [ -z "$SKIP_PROXY_TESTS" ]; then
-       curl --location --silent --show-error https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar
-
-       echo ""
-       echo "Starting HTTP proxy (Basic)..."
-       java -jar poxyproxy.jar --address 127.0.0.1 --port 8080 --credentials foo:bar --auth-type basic --quiet &
-
-       echo ""
-       echo "Starting HTTP proxy (NTLM)..."
-       java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet &
-fi
-
-if [ -z "$SKIP_NTLM_TESTS" ]; then
-       curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar
-
-       echo ""
-       echo "Starting HTTP server..."
-       NTLM_DIR=`mktemp -d ${TMPDIR}/ntlm.XXXXXXXX`
-       git init --bare "${NTLM_DIR}/test.git"
-       java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${NTLM_DIR}" &
-fi
-
-if [ -z "$SKIP_SSH_TESTS" ]; then
-       echo "Starting ssh daemon..."
-       HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX`
-       SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
-       git init --bare "${SSHD_DIR}/test.git"
-       cat >"${SSHD_DIR}/sshd_config" <<-EOF
-       Port 2222
-       ListenAddress 0.0.0.0
-       Protocol 2
-       HostKey ${SSHD_DIR}/id_rsa
-       PidFile ${SSHD_DIR}/pid
-       AuthorizedKeysFile ${HOME}/.ssh/authorized_keys
-       LogLevel DEBUG
-       RSAAuthentication yes
-       PasswordAuthentication yes
-       PubkeyAuthentication yes
-       ChallengeResponseAuthentication no
-       StrictModes no
-       # Required here as sshd will simply close connection otherwise
-       UsePAM no
-       EOF
-       ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q
-       /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log"
-
-       # Set up keys
-       mkdir "${HOME}/.ssh"
-       ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q
-       cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys"
-       while read algorithm key comment; do
-               echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts"
-       done <"${SSHD_DIR}/id_rsa.pub"
-
-       # Get the fingerprint for localhost and remove the colons so we can
-       # parse it as a hex number. Older versions have a different output
-       # format.
-       if [[ $(ssh -V 2>&1) == OpenSSH_6* ]]; then
-               SSH_FINGERPRINT=$(ssh-keygen -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
-       else
-               SSH_FINGERPRINT=$(ssh-keygen -E md5 -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :)
-       fi
-fi
-
-# Run the tests that do not require network connectivity.
-
-if [ -z "$SKIP_OFFLINE_TESTS" ]; then
-       echo ""
-       echo "##############################################################################"
-       echo "## Running (offline) tests"
-       echo "##############################################################################"
-
-       run_test offline
-fi
-
-if [ -n "$RUN_INVASIVE_TESTS" ]; then
-       echo ""
-       echo "Running invasive tests"
-       echo ""
-
-       export GITTEST_INVASIVE_FS_SIZE=1
-       export GITTEST_INVASIVE_MEMORY=1
-       export GITTEST_INVASIVE_SPEED=1
-       run_test invasive
-       unset GITTEST_INVASIVE_FS_SIZE
-       unset GITTEST_INVASIVE_MEMORY
-       unset GITTEST_INVASIVE_SPEED
-fi
-
-if [ -z "$SKIP_ONLINE_TESTS" ]; then
-       # Run the various online tests.  The "online" test suite only includes the
-       # default online tests that do not require additional configuration.  The
-       # "proxy" and "ssh" test suites require further setup.
-
-       echo ""
-       echo "##############################################################################"
-       echo "## Running (online) tests"
-       echo "##############################################################################"
-
-       export GITTEST_FLAKY_RETRY=5
-       run_test online
-       unset GITTEST_FLAKY_RETRY
-fi
-
-if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
-       echo ""
-       echo "Running gitdaemon tests"
-       echo ""
-
-       export GITTEST_REMOTE_URL="git://localhost/test.git"
-       run_test gitdaemon
-       unset GITTEST_REMOTE_URL
-fi
-
-if [ -z "$SKIP_PROXY_TESTS" ]; then
-       echo ""
-       echo "Running proxy tests (Basic authentication)"
-       echo ""
-
-       export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
-       export GITTEST_REMOTE_PROXY_USER="foo"
-       export GITTEST_REMOTE_PROXY_PASS="bar"
-       run_test proxy
-       unset GITTEST_REMOTE_PROXY_HOST
-       unset GITTEST_REMOTE_PROXY_USER
-       unset GITTEST_REMOTE_PROXY_PASS
-
-       echo ""
-       echo "Running proxy tests (NTLM authentication)"
-       echo ""
-
-       export GITTEST_REMOTE_PROXY_HOST="localhost:8090"
-       export GITTEST_REMOTE_PROXY_USER="foo"
-       export GITTEST_REMOTE_PROXY_PASS="bar"
-       export GITTEST_FLAKY_RETRY=5
-       run_test proxy
-       unset GITTEST_FLAKY_RETRY
-       unset GITTEST_REMOTE_PROXY_HOST
-       unset GITTEST_REMOTE_PROXY_USER
-       unset GITTEST_REMOTE_PROXY_PASS
-fi
-
-if [ -z "$SKIP_NTLM_TESTS" ]; then
-       echo ""
-       echo "Running NTLM tests (IIS emulation)"
-       echo ""
-
-       export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git"
-       export GITTEST_REMOTE_USER="foo"
-       export GITTEST_REMOTE_PASS="baz"
-       run_test auth_clone_and_push
-       unset GITTEST_REMOTE_URL
-       unset GITTEST_REMOTE_USER
-       unset GITTEST_REMOTE_PASS
-
-       echo ""
-       echo "Running NTLM tests (Apache emulation)"
-       echo ""
-
-       export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git"
-       export GITTEST_REMOTE_USER="foo"
-       export GITTEST_REMOTE_PASS="baz"
-       run_test auth_clone_and_push
-       unset GITTEST_REMOTE_URL
-       unset GITTEST_REMOTE_USER
-       unset GITTEST_REMOTE_PASS
-fi
-
-if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then
-       echo ""
-       echo "Running SPNEGO tests"
-       echo ""
-
-       if [ "$(uname -s)" = "Darwin" ]; then
-               KINIT_FLAGS="--password-file=STDIN"
-       fi
-
-       echo $GITTEST_NEGOTIATE_PASSWORD | kinit $KINIT_FLAGS test@LIBGIT2.ORG
-       klist -5f
-
-       export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
-       export GITTEST_REMOTE_DEFAULT="true"
-       run_test auth_clone
-       unset GITTEST_REMOTE_URL
-       unset GITTEST_REMOTE_DEFAULT
-
-       echo ""
-       echo "Running SPNEGO tests (expect/continue)"
-       echo ""
-
-       export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
-       export GITTEST_REMOTE_DEFAULT="true"
-       export GITTEST_REMOTE_EXPECTCONTINUE="true"
-       run_test auth_clone
-       unset GITTEST_REMOTE_URL
-       unset GITTEST_REMOTE_DEFAULT
-       unset GITTEST_REMOTE_EXPECTCONTINUE
-
-       kdestroy -A
-fi
-
-if [ -z "$SKIP_SSH_TESTS" ]; then
-       echo ""
-       echo "Running ssh tests"
-       echo ""
-
-       export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git"
-       export GITTEST_REMOTE_USER=$USER
-       export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa"
-       export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub"
-       export GITTEST_REMOTE_SSH_PASSPHRASE=""
-       export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}"
-       run_test ssh
-       unset GITTEST_REMOTE_URL
-       unset GITTEST_REMOTE_USER
-       unset GITTEST_REMOTE_SSH_KEY
-       unset GITTEST_REMOTE_SSH_PUBKEY
-       unset GITTEST_REMOTE_SSH_PASSPHRASE
-       unset GITTEST_REMOTE_SSH_FINGERPRINT
-fi
-
-if [ -z "$SKIP_FUZZERS" ]; then
-       echo ""
-       echo "##############################################################################"
-       echo "## Running fuzzers"
-       echo "##############################################################################"
-
-       ctest -V -R 'fuzzer'
-fi
-
-cleanup
-
-if [ "$SUCCESS" -ne 1 ]; then
-       echo "Some tests failed."
-       exit 1
-fi
-
-echo "Success."
-exit 0
diff --git a/ci/build.sh b/ci/build.sh
new file mode 100755 (executable)
index 0000000..5a51f92
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+#
+# Environment variables:
+#
+# SOURCE_DIR: Set to the directory of the libgit2 source (optional)
+#     If not set, it will be derived relative to this script.
+
+set -e
+
+SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
+BUILD_DIR=$(pwd)
+BUILD_PATH=${BUILD_PATH:=$PATH}
+CMAKE=$(which cmake)
+CMAKE_GENERATOR=${CMAKE_GENERATOR:-Unix Makefiles}
+
+if [[ "$(uname -s)" == MINGW* ]]; then
+       BUILD_PATH=$(cygpath "$BUILD_PATH")
+fi
+
+indent() { sed "s/^/    /"; }
+
+echo "Source directory: ${SOURCE_DIR}"
+echo "Build directory:  ${BUILD_DIR}"
+echo ""
+
+if [ "$(uname -s)" = "Darwin" ]; then
+       echo "macOS version:"
+       sw_vers | indent
+fi
+
+if [ -f "/etc/debian_version" ]; then
+       echo "Debian version:"
+       (source /etc/lsb-release && echo "${DISTRIB_DESCRIPTION}") | indent
+fi
+
+CORES=$(getconf _NPROCESSORS_ONLN || true)
+echo "Number of cores: ${CORES:-(Unknown)}"
+
+echo "Kernel version:"
+uname -a 2>&1 | indent
+
+echo "CMake version:"
+env PATH="${BUILD_PATH}" "${CMAKE}" --version 2>&1 | indent
+
+if test -n "${CC}"; then
+       echo "Compiler version:"
+       "${CC}" --version 2>&1 | indent
+fi
+echo "Environment:"
+if test -n "${CC}"; then
+       echo "CC=${CC}" | indent
+fi
+if test -n "${CFLAGS}"; then
+       echo "CFLAGS=${CFLAGS}" | indent
+fi
+echo ""
+
+echo "##############################################################################"
+echo "## Configuring build environment"
+echo "##############################################################################"
+
+echo cmake -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS} -S \"${SOURCE_DIR}\"
+env PATH="${BUILD_PATH}" "${CMAKE}" -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G "${CMAKE_GENERATOR}" ${CMAKE_OPTIONS} -S "${SOURCE_DIR}"
+
+echo ""
+echo "##############################################################################"
+echo "## Building libgit2"
+echo "##############################################################################"
+
+# Determine parallelism; newer cmake supports `--build --parallel` but
+# we cannot yet rely on that.
+if [ "${CMAKE_GENERATOR}" = "Unix Makefiles" -a "${CORES}" != "" ]; then
+       BUILDER=(make -j ${CORES})
+else
+       BUILDER=("${CMAKE}" --build .)
+fi
+
+env PATH="${BUILD_PATH}" "${BUILDER[@]}"
diff --git a/ci/coverity.sh b/ci/coverity.sh
new file mode 100755 (executable)
index 0000000..c68b6f8
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+
+if test -z "$COVERITY_TOKEN"
+then
+    echo "Need to set a coverity token"
+    exit 1
+fi
+
+case $(uname -m) in
+    i?86)
+        BITS=32;;
+    amd64|x86_64)
+        BITS=64;;
+    *)
+        echo "Unsupported arch '$(uname -m)'"
+        exit 1;;
+esac
+
+SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
+SOURCE_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")"/..)
+BUILD_DIR=${SOURCE_DIR}/coverity-build
+TOOL_DIR=${BUILD_DIR}/coverity-tools
+
+# Install coverity tools
+if ! test -d "$TOOL_DIR"
+then
+    mkdir -p "$TOOL_DIR"
+    curl --silent --show-error --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" |
+        tar -xzC "$TOOL_DIR"
+    ln -s "$(find "$TOOL_DIR" -type d -name 'cov-analysis*')" "$TOOL_DIR"/cov-analysis
+fi
+
+cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_DIR"/cov-analysis/config/
+
+# Build libgit2 with Coverity
+mkdir -p "$BUILD_DIR"
+cd "$BUILD_DIR"
+cmake "$SOURCE_DIR"
+COVERITY_UNSUPPORTED=1 \
+    "$TOOL_DIR/cov-analysis/bin/cov-build" --dir cov-int \
+    cmake --build .
+
+# Upload results
+tar -czf libgit2.tgz cov-int
+REVISION=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
+HTML="$(curl \
+    --silent --show-error \
+    --write-out "\n%{http_code}" \
+    --form token="$COVERITY_TOKEN" \
+    --form email=libgit2@gmail.com \
+    --form file=@libgit2.tgz \
+    --form version="$REVISION" \
+    --form description="libgit2 build" \
+    https://scan.coverity.com/builds?project=libgit2)"
+
+# Status code is the last line
+STATUS_CODE="$(echo "$HTML" | tail -n1)"
+if test "${STATUS_CODE}" != 200 && test "${STATUS_CODE}" != 201
+then
+    echo "Received error code ${STATUS_CODE} from Coverity"
+    exit 1
+fi
diff --git a/ci/docker/bionic b/ci/docker/bionic
new file mode 100644 (file)
index 0000000..51af5c0
--- /dev/null
@@ -0,0 +1,44 @@
+ARG BASE=ubuntu:bionic
+
+FROM ${BASE} AS apt
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+        clang \
+        cmake \
+        curl \
+        gcc \
+        git \
+        krb5-user \
+        libcurl4-openssl-dev \
+        libkrb5-dev \
+        libpcre3-dev \
+        libssh2-1-dev \
+        libssl-dev \
+        libz-dev \
+        ninja-build \
+        openjdk-8-jre-headless \
+        openssh-server \
+        openssl \
+        pkgconf \
+        python \
+        sudo \
+        valgrind \
+        && \
+    rm -rf /var/lib/apt/lists/*
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+    tar -xz && \
+    cd mbedtls-2.16.2 && \
+    scripts/config.pl set MBEDTLS_MD4_C 1 && \
+    CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
+    ninja install && \
+    cd .. && \
+    rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS adduser
+RUN useradd --shell /bin/bash libgit2 --create-home
+
+FROM adduser AS configure
+RUN mkdir /var/run/sshd
diff --git a/ci/docker/centos7 b/ci/docker/centos7
new file mode 100644 (file)
index 0000000..8105f14
--- /dev/null
@@ -0,0 +1,55 @@
+ARG BASE=centos:7
+
+FROM ${BASE} AS yum
+RUN yum install -y \
+       which \
+       bzip2 \
+       git \
+       libarchive \
+       gcc \
+       gcc-c++ \
+       make \
+       openssl-devel \
+       openssh-server \
+       git-daemon \
+       java-1.8.0-openjdk-headless \
+       sudo \
+       python
+
+FROM yum AS libssh2
+RUN cd /tmp && \
+    curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \
+    cd libssh2-1.8.0 && \
+    ./configure && \
+    make && \
+    make install && \
+    cd .. && \
+    rm -rf libssh-1.8.0
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+        tar -xj && \
+    cd valgrind-3.15.0 && \
+    ./configure && \
+    make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \
+    make install && \
+    cd .. && \
+    rm -rf valgrind-3.15.0
+
+FROM valgrind AS cmake
+RUN cd /tmp && \
+    curl -L https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1.tar.gz | tar -xz && \
+    cd cmake-3.21.1 && \
+    ./configure && \
+    make && \
+    make install && \
+    cd .. && \
+    rm -rf cmake-3.21.1
+
+FROM cmake AS adduser
+RUN useradd --shell /bin/bash libgit2 --create-home
+
+FROM adduser AS configure
+ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig
+RUN mkdir /var/run/sshd
diff --git a/ci/docker/centos8 b/ci/docker/centos8
new file mode 100644 (file)
index 0000000..cca0881
--- /dev/null
@@ -0,0 +1,49 @@
+ARG BASE=centos:8
+
+FROM ${BASE} AS yum
+RUN yum install -y \
+       which \
+       bzip2 \
+       git \
+       libarchive \
+       cmake \
+       gcc \
+       make \
+       openssl-devel \
+       openssh-server \
+       git-daemon \
+       java-1.8.0-openjdk-headless \
+       sudo \
+       python39 \
+       krb5-workstation \
+       krb5-libs
+
+FROM yum AS libssh2
+RUN cd /tmp && \
+    curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \
+    cd libssh2-1.8.0 && \
+    ./configure && \
+    make && \
+    make install && \
+    cd .. && \
+    rm -rf libssh2-1.8.0
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+        tar -xj && \
+    cd valgrind-3.15.0 && \
+    ./configure && \
+    make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \
+    make install && \
+    cd .. && \
+    rm -rf valgrind-3.15.0
+
+FROM valgrind AS adduser
+RUN useradd --shell /bin/bash libgit2 --create-home
+
+FROM adduser AS configure
+ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig
+RUN mkdir /var/run/sshd
+RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/local && \
+    ldconfig
diff --git a/ci/docker/docurium b/ci/docker/docurium
new file mode 100644 (file)
index 0000000..1957bbb
--- /dev/null
@@ -0,0 +1,5 @@
+ARG BASE=ubuntu:bionic
+
+FROM ${BASE}
+RUN apt update && apt install -y cmake pkg-config ruby ruby-dev llvm libclang-dev libssl-dev python-pygments
+RUN gem install docurium
diff --git a/ci/docker/focal b/ci/docker/focal
new file mode 100644 (file)
index 0000000..37d7d63
--- /dev/null
@@ -0,0 +1,79 @@
+ARG BASE=ubuntu:focal
+
+FROM ${BASE} AS apt
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+        bzip2 \
+        clang-10 \
+        cmake \
+        curl \
+        gcc-10 \
+        git \
+        krb5-user \
+        libcurl4-gnutls-dev \
+        libgcrypt20-dev \
+        libkrb5-dev \
+        libpcre3-dev \
+        libssl-dev \
+        libz-dev \
+        llvm-10 \
+        make \
+        ninja-build \
+        openjdk-8-jre-headless \
+        openssh-server \
+        openssl \
+        pkgconf \
+        python \
+        sudo \
+        valgrind \
+        && \
+    rm -rf /var/lib/apt/lists/* && \
+    mkdir /usr/local/msan
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+        tar -xz && \
+    cd mbedtls-2.16.2 && \
+    scripts/config.pl unset MBEDTLS_AESNI_C && \
+    scripts/config.pl set MBEDTLS_MD4_C 1 && \
+    mkdir build build-msan && \
+    cd build && \
+    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
+    ninja install && \
+    cd ../build-msan && \
+    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
+    ninja install && \
+    cd .. && \
+    rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS libssh2
+RUN cd /tmp && \
+    curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.9.0.tar.gz | tar -xz && \
+    cd libssh2-1.9.0 && \
+    mkdir build build-msan && \
+    cd build && \
+    CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
+    ninja install && \
+    cd ../build-msan && \
+    CC=clang-10 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
+    ninja install && \
+    cd .. && \
+    rm -rf libssh2-1.9.0
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+        tar -xj && \
+    cd valgrind-3.15.0 && \
+    CC=clang-10 ./configure && \
+    make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \
+    make install && \
+    cd .. && \
+    rm -rf valgrind-3.15.0
+
+FROM valgrind AS adduser
+RUN useradd --shell /bin/bash libgit2 --create-home
+
+FROM adduser AS configure
+RUN mkdir /var/run/sshd
diff --git a/ci/docker/xenial b/ci/docker/xenial
new file mode 100644 (file)
index 0000000..c19fe42
--- /dev/null
@@ -0,0 +1,66 @@
+ARG BASE=ubuntu:xenial
+
+FROM ${BASE} AS apt
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+        bzip2 \
+        clang \
+        cmake \
+        curl \
+        gcc \
+        git \
+        krb5-user \
+        libcurl4-gnutls-dev \
+        libgcrypt20-dev \
+        libkrb5-dev \
+        libpcre3-dev \
+        libssl-dev \
+        libz-dev \
+        make \
+        ninja-build \
+        openjdk-8-jre-headless \
+        openssh-server \
+        openssl \
+        pkgconf \
+        python \
+        sudo \
+        valgrind \
+        && \
+    rm -rf /var/lib/apt/lists/*
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+    curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+    tar -xz && \
+    cd mbedtls-2.16.2 && \
+    scripts/config.pl set MBEDTLS_MD4_C 1 && \
+    CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
+    ninja install && \
+    cd .. && \
+    rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS libssh2
+RUN cd /tmp && \
+    curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | tar -xz && \
+    cd libssh2-1.8.2 && \
+    CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \
+    ninja install && \
+    cd .. && \
+    rm -rf libssh2-1.8.2
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+    curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+    tar -xj && \
+    cd valgrind-3.15.0 && \
+    ./configure && \
+    make && \
+    make install && \
+    cd .. && \
+    rm -rf valgrind-3.15.0
+
+FROM valgrind AS adduser
+RUN useradd --shell /bin/bash libgit2 --create-home
+
+FROM adduser AS configure
+RUN mkdir /var/run/sshd
diff --git a/ci/getcontainer.sh b/ci/getcontainer.sh
new file mode 100755 (executable)
index 0000000..07ef7b8
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+set -e
+
+IMAGE_NAME=$1
+DOCKERFILE_PATH=$2
+
+if [ "${IMAGE_NAME}" = "" ]; then
+       echo "usage: $0 image_name [dockerfile]"
+       exit 1
+fi
+
+if [ "${DOCKERFILE_PATH}" = "" ]; then
+       DOCKERFILE_PATH="${IMAGE_NAME}"
+fi
+
+if [ "${DOCKER_REGISTRY}" = "" ]; then
+       echo "DOCKER_REGISTRY environment variable is unset."
+       echo "Not running inside GitHub Actions or misconfigured?"
+       exit 1
+fi
+
+DOCKER_CONTAINER="${GITHUB_REPOSITORY}/${IMAGE_NAME}"
+DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}"
+
+echo "dockerfile=${DOCKERFILE_PATH}" >> $GITHUB_ENV
+echo "docker-container=${DOCKER_CONTAINER}" >> $GITHUB_ENV
+echo "docker-registry-container=${DOCKER_REGISTRY_CONTAINER}" >> $GITHUB_ENV
+
+# Identify the last git commit that touched the Dockerfiles
+# Use this as a hash to identify the resulting docker containers
+DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}")
+echo "docker-sha=${DOCKER_SHA}" >> $GITHUB_ENV
+
+DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}"
+
+echo "docker-registry-container-sha=${DOCKER_REGISTRY_CONTAINER_SHA}" >> $GITHUB_ENV
+echo "docker-registry-container-latest=${DOCKER_REGISTRY_CONTAINER}:latest" >> $GITHUB_ENV
+
+exists="true"
+docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false"
+
+if [ "${exists}" != "false" ]; then
+       docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false"
+fi
+
+if [ "${exists}" = "true" ]; then
+       echo "docker-container-exists=true" >> $GITHUB_ENV
+else
+       echo "docker-container-exists=false" >> $GITHUB_ENV
+fi
diff --git a/ci/setup-mingw.sh b/ci/setup-mingw.sh
new file mode 100755 (executable)
index 0000000..f5a882d
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh -e
+
+echo "##############################################################################"
+echo "## Downloading mingw"
+echo "##############################################################################"
+
+BUILD_TEMP=${BUILD_TEMP:=$TEMP}
+BUILD_TEMP=$(cygpath $BUILD_TEMP)
+
+case "$ARCH" in
+       amd64)
+               MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2021-05-04/mingw-x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";;
+       x86)
+               MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2021-05-04/mingw-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";;
+esac
+
+if [ -z "$MINGW_URI" ]; then
+       echo "No URL"
+       exit 1
+fi
+
+mkdir -p "$BUILD_TEMP"
+
+curl -s -L "$MINGW_URI" -o "$BUILD_TEMP"/mingw-"$ARCH".zip
+unzip -q "$BUILD_TEMP"/mingw-"$ARCH".zip -d "$BUILD_TEMP"
diff --git a/ci/setup-osx.sh b/ci/setup-osx.sh
new file mode 100755 (executable)
index 0000000..2e630ee
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -x
+
+brew update
+brew install pkgconfig zlib curl openssl libssh2 ninja
+
+ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib
diff --git a/ci/test.sh b/ci/test.sh
new file mode 100755 (executable)
index 0000000..4d6c41f
--- /dev/null
@@ -0,0 +1,338 @@
+#!/usr/bin/env bash
+
+set -e
+
+if [ -n "$SKIP_TESTS" ]; then
+       exit 0
+fi
+
+# Windows doesn't run the NTLM tests properly (yet)
+if [[ "$(uname -s)" == MINGW* ]]; then
+        SKIP_NTLM_TESTS=1
+fi
+
+SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
+BUILD_DIR=$(pwd)
+TMPDIR=${TMPDIR:-/tmp}
+USER=${USER:-$(whoami)}
+
+SUCCESS=1
+CONTINUE_ON_FAILURE=0
+
+cleanup() {
+       echo "Cleaning up..."
+
+       if [ ! -z "$GITDAEMON_PID" ]; then
+               echo "Stopping git daemon..."
+               kill $GITDAEMON_PID
+       fi
+
+       if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then
+               echo "Stopping SSH..."
+               kill $(cat "${SSHD_DIR}/pid")
+       fi
+
+       echo "Done."
+}
+
+run_test() {
+       if [[ "$GITTEST_FLAKY_RETRY" > 0 ]]; then
+               ATTEMPTS_REMAIN=$GITTEST_FLAKY_RETRY
+       else
+               ATTEMPTS_REMAIN=1
+       fi
+
+       FAILED=0
+       while [[ "$ATTEMPTS_REMAIN" > 0 ]]; do
+               if [ "$FAILED" -eq 1 ]; then
+                       echo ""
+                       echo "Re-running flaky ${1} tests..."
+                       echo ""
+               fi
+
+               RETURN_CODE=0
+
+               CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" ctest -V -R "^${1}$" || RETURN_CODE=$? && true
+
+               if [ "$RETURN_CODE" -eq 0 ]; then
+                       FAILED=0
+                       break
+               fi
+
+               echo "Test exited with code: $RETURN_CODE"
+               ATTEMPTS_REMAIN="$(($ATTEMPTS_REMAIN-1))"
+               FAILED=1
+       done
+
+       if [ "$FAILED" -ne 0 ]; then
+               if [ "$CONTINUE_ON_FAILURE" -ne 1 ]; then
+                       exit 1
+               fi
+
+               SUCCESS=0
+       fi
+}
+
+# Configure the test environment; run them early so that we're certain
+# that they're started by the time we need them.
+
+echo "##############################################################################"
+echo "## Configuring test environment"
+echo "##############################################################################"
+
+if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
+       echo "Starting git daemon..."
+       GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
+       git init --bare "${GITDAEMON_DIR}/test.git"
+       git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
+       GITDAEMON_PID=$!
+       disown $GITDAEMON_PID
+fi
+
+if [ -z "$SKIP_PROXY_TESTS" ]; then
+       curl --location --silent --show-error https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar
+
+       echo ""
+       echo "Starting HTTP proxy (Basic)..."
+       java -jar poxyproxy.jar --address 127.0.0.1 --port 8080 --credentials foo:bar --auth-type basic --quiet &
+
+       echo ""
+       echo "Starting HTTP proxy (NTLM)..."
+       java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet &
+fi
+
+if [ -z "$SKIP_NTLM_TESTS" ]; then
+       curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar
+
+       echo ""
+       echo "Starting HTTP server..."
+       NTLM_DIR=`mktemp -d ${TMPDIR}/ntlm.XXXXXXXX`
+       git init --bare "${NTLM_DIR}/test.git"
+       java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${NTLM_DIR}" &
+fi
+
+if [ -z "$SKIP_SSH_TESTS" ]; then
+       echo "Starting ssh daemon..."
+       HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX`
+       SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
+       git init --bare "${SSHD_DIR}/test.git"
+       cat >"${SSHD_DIR}/sshd_config" <<-EOF
+       Port 2222
+       ListenAddress 0.0.0.0
+       Protocol 2
+       HostKey ${SSHD_DIR}/id_rsa
+       PidFile ${SSHD_DIR}/pid
+       AuthorizedKeysFile ${HOME}/.ssh/authorized_keys
+       LogLevel DEBUG
+       RSAAuthentication yes
+       PasswordAuthentication yes
+       PubkeyAuthentication yes
+       ChallengeResponseAuthentication no
+       StrictModes no
+       # Required here as sshd will simply close connection otherwise
+       UsePAM no
+       EOF
+       ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q
+       /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log"
+
+       # Set up keys
+       mkdir "${HOME}/.ssh"
+       ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q
+       cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys"
+       while read algorithm key comment; do
+               echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts"
+       done <"${SSHD_DIR}/id_rsa.pub"
+
+       # Get the fingerprint for localhost and remove the colons so we can
+       # parse it as a hex number. Older versions have a different output
+       # format.
+       if [[ $(ssh -V 2>&1) == OpenSSH_6* ]]; then
+               SSH_FINGERPRINT=$(ssh-keygen -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
+       else
+               SSH_FINGERPRINT=$(ssh-keygen -E md5 -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :)
+       fi
+fi
+
+# Run the tests that do not require network connectivity.
+
+if [ -z "$SKIP_OFFLINE_TESTS" ]; then
+       echo ""
+       echo "##############################################################################"
+       echo "## Running (offline) tests"
+       echo "##############################################################################"
+
+       run_test offline
+fi
+
+if [ -n "$RUN_INVASIVE_TESTS" ]; then
+       echo ""
+       echo "Running invasive tests"
+       echo ""
+
+       export GITTEST_INVASIVE_FS_SIZE=1
+       export GITTEST_INVASIVE_MEMORY=1
+       export GITTEST_INVASIVE_SPEED=1
+       run_test invasive
+       unset GITTEST_INVASIVE_FS_SIZE
+       unset GITTEST_INVASIVE_MEMORY
+       unset GITTEST_INVASIVE_SPEED
+fi
+
+if [ -z "$SKIP_ONLINE_TESTS" ]; then
+       # Run the online tests.  The "online" test suite only includes the
+       # default online tests that do not require additional configuration.
+       # The "proxy" and "ssh" test suites require further setup.
+
+       echo ""
+       echo "##############################################################################"
+       echo "## Running (online) tests"
+       echo "##############################################################################"
+
+       export GITTEST_FLAKY_RETRY=5
+       run_test online
+       unset GITTEST_FLAKY_RETRY
+
+       # Run the online tests that immutably change global state separately
+       # to avoid polluting the test environment.
+       echo ""
+       echo "##############################################################################"
+       echo "## Running (online_customcert) tests"
+       echo "##############################################################################"
+       run_test online_customcert
+fi
+
+if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
+       echo ""
+       echo "Running gitdaemon tests"
+       echo ""
+
+       export GITTEST_REMOTE_URL="git://localhost/test.git"
+       run_test gitdaemon
+       unset GITTEST_REMOTE_URL
+fi
+
+if [ -z "$SKIP_PROXY_TESTS" ]; then
+       echo ""
+       echo "Running proxy tests (Basic authentication)"
+       echo ""
+
+       export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
+       export GITTEST_REMOTE_PROXY_USER="foo"
+       export GITTEST_REMOTE_PROXY_PASS="bar"
+       run_test proxy
+       unset GITTEST_REMOTE_PROXY_HOST
+       unset GITTEST_REMOTE_PROXY_USER
+       unset GITTEST_REMOTE_PROXY_PASS
+
+       echo ""
+       echo "Running proxy tests (NTLM authentication)"
+       echo ""
+
+       export GITTEST_REMOTE_PROXY_HOST="localhost:8090"
+       export GITTEST_REMOTE_PROXY_USER="foo"
+       export GITTEST_REMOTE_PROXY_PASS="bar"
+       export GITTEST_FLAKY_RETRY=5
+       run_test proxy
+       unset GITTEST_FLAKY_RETRY
+       unset GITTEST_REMOTE_PROXY_HOST
+       unset GITTEST_REMOTE_PROXY_USER
+       unset GITTEST_REMOTE_PROXY_PASS
+fi
+
+if [ -z "$SKIP_NTLM_TESTS" ]; then
+       echo ""
+       echo "Running NTLM tests (IIS emulation)"
+       echo ""
+
+       export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git"
+       export GITTEST_REMOTE_USER="foo"
+       export GITTEST_REMOTE_PASS="baz"
+       run_test auth_clone_and_push
+       unset GITTEST_REMOTE_URL
+       unset GITTEST_REMOTE_USER
+       unset GITTEST_REMOTE_PASS
+
+       echo ""
+       echo "Running NTLM tests (Apache emulation)"
+       echo ""
+
+       export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git"
+       export GITTEST_REMOTE_USER="foo"
+       export GITTEST_REMOTE_PASS="baz"
+       run_test auth_clone_and_push
+       unset GITTEST_REMOTE_URL
+       unset GITTEST_REMOTE_USER
+       unset GITTEST_REMOTE_PASS
+fi
+
+if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then
+       echo ""
+       echo "Running SPNEGO tests"
+       echo ""
+
+       if [ "$(uname -s)" = "Darwin" ]; then
+               KINIT_FLAGS="--password-file=STDIN"
+       fi
+
+       echo $GITTEST_NEGOTIATE_PASSWORD | kinit $KINIT_FLAGS test@LIBGIT2.ORG
+       klist -5f
+
+       export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
+       export GITTEST_REMOTE_DEFAULT="true"
+       run_test auth_clone
+       unset GITTEST_REMOTE_URL
+       unset GITTEST_REMOTE_DEFAULT
+
+       echo ""
+       echo "Running SPNEGO tests (expect/continue)"
+       echo ""
+
+       export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
+       export GITTEST_REMOTE_DEFAULT="true"
+       export GITTEST_REMOTE_EXPECTCONTINUE="true"
+       run_test auth_clone
+       unset GITTEST_REMOTE_URL
+       unset GITTEST_REMOTE_DEFAULT
+       unset GITTEST_REMOTE_EXPECTCONTINUE
+
+       kdestroy -A
+fi
+
+if [ -z "$SKIP_SSH_TESTS" ]; then
+       echo ""
+       echo "Running ssh tests"
+       echo ""
+
+       export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git"
+       export GITTEST_REMOTE_USER=$USER
+       export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa"
+       export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub"
+       export GITTEST_REMOTE_SSH_PASSPHRASE=""
+       export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}"
+       run_test ssh
+       unset GITTEST_REMOTE_URL
+       unset GITTEST_REMOTE_USER
+       unset GITTEST_REMOTE_SSH_KEY
+       unset GITTEST_REMOTE_SSH_PUBKEY
+       unset GITTEST_REMOTE_SSH_PASSPHRASE
+       unset GITTEST_REMOTE_SSH_FINGERPRINT
+fi
+
+if [ -z "$SKIP_FUZZERS" ]; then
+       echo ""
+       echo "##############################################################################"
+       echo "## Running fuzzers"
+       echo "##############################################################################"
+
+       ctest -V -R 'fuzzer'
+fi
+
+cleanup
+
+if [ "$SUCCESS" -ne 1 ]; then
+       echo "Some tests failed."
+       exit 1
+fi
+
+echo "Success."
+exit 0
diff --git a/cmake/FindLibSSH2.cmake b/cmake/FindLibSSH2.cmake
new file mode 100644 (file)
index 0000000..ff58935
--- /dev/null
@@ -0,0 +1,13 @@
+# LIBSSH2_FOUND - system has the libssh2 library
+# LIBSSH2_INCLUDE_DIR - the libssh2 include directory
+# LIBSSH2_LIBRARY - the libssh2 library name
+
+FIND_PATH(LIBSSH2_INCLUDE_DIR libssh2.h)
+
+FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2 libssh2)
+
+INCLUDE(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LibSSH2
+    REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR)
+
+MARK_AS_ADVANCED(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)
diff --git a/cmake/Findfutimens.cmake b/cmake/Findfutimens.cmake
new file mode 100644 (file)
index 0000000..73b7952
--- /dev/null
@@ -0,0 +1,14 @@
+INCLUDE(EnableWarnings)
+
+IF (APPLE)
+       # We cannot simply CHECK_FUNCTION_EXISTS on macOS because
+       # MACOSX_DEPLOYMENT_TARGET may be set to a version in the past
+       # that doesn't have futimens.  Instead we need to enable warnings
+       # as errors, then check for the symbol existing in `sys/stat.h`,
+       # then reset warnings as errors.
+       ENABLE_WARNINGS(error)
+       CHECK_SYMBOL_EXISTS(futimens sys/stat.h HAVE_FUTIMENS)
+       DISABLE_WARNINGS(error)
+ELSE ()
+       CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
+ENDIF ()
index afbeac42445609cf09adc3663736f4afa6f40460..4998f0f2ac92154bc3e40860175ccee2ac91a6d9 100644 (file)
@@ -108,6 +108,10 @@ IF(USE_HTTPS)
                LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
        ELSEIF (USE_HTTPS STREQUAL "WinHTTP")
                # WinHTTP setup was handled in the WinHTTP-specific block above
+       ELSEIF (USE_HTTPS STREQUAL "OpenSSL-Dynamic")
+               SET(GIT_OPENSSL 1)
+               SET(GIT_OPENSSL_DYNAMIC 1)
+               LIST(APPEND LIBGIT2_LIBS dl)
        ELSE()
                MESSAGE(FATAL_ERROR "Asked for backend ${USE_HTTPS} but it wasn't found")
        ENDIF()
index 06672ab0339c393a9bd81cdb134389e08675cc2d..092cdfd051a956a5e4cb7c283afd84c36fe1bd82 100644 (file)
@@ -56,6 +56,7 @@ ELSE()
        MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}")
 ENDIF()
 
+list(APPEND SRC_SHA1 "hash/sha1.h")
 list(SORT SRC_SHA1)
 
 ADD_FEATURE_INFO(SHA ON "using ${USE_SHA1}")
index 288ef2d115b2c27670d09d708089a7bf3f525569..8060874df0eceeaddb5f4198635802c76e0bea19 100644 (file)
@@ -1,3 +1,235 @@
+v1.3
+----
+
+This is release v1.3.0, "Zugunruhe".  This release includes only minor new features that will be helpful for users to have an orderly transition to the v2.0 lineage.
+
+## New Features
+* Support custom git extensions by @ethomson in https://github.com/libgit2/libgit2/pull/6031
+* Introduce `git_email_create`; deprecate `git_diff_format_email` by @ethomson in https://github.com/libgit2/libgit2/pull/6061
+
+## Deprecated APIs
+* `git_oidarray_free` is deprecated; callers should use `git_oidarray_dispose`
+
+## Bug fixes
+* #6028: Check if `threadstate->error_t.message` is not `git_buf__initbuf` before freeing. by @arroz in https://github.com/libgit2/libgit2/pull/6029
+* remote: Mark `git_remote_name_is_valid` as `GIT_EXTERN` by @lhchavez in https://github.com/libgit2/libgit2/pull/6032
+* Fix config parsing for multiline with multiple quoted comment chars by @basile-henry in https://github.com/libgit2/libgit2/pull/6043
+* indexer: Avoid one `mmap(2)`/`munmap(2)` pair per `git_indexer_append` call by @lhchavez in https://github.com/libgit2/libgit2/pull/6039
+* merge: Check file mode when resolving renames by @ccstolley in https://github.com/libgit2/libgit2/pull/6060
+* Allow proxy options when connecting with a detached remote. by @lrm29 in https://github.com/libgit2/libgit2/pull/6058
+* win32: allow empty environment variables by @ethomson in https://github.com/libgit2/libgit2/pull/6063
+* Fixes for deprecated APIs by @ethomson in https://github.com/libgit2/libgit2/pull/6066
+* filter: use a `git_oid` in filter options, not a pointer by @ethomson in https://github.com/libgit2/libgit2/pull/6067
+* diff: update `GIT_DIFF_IGNORE_BLANK_LINES` by @ethomson in https://github.com/libgit2/libgit2/pull/6068 
+* Attribute lookups are always on relative paths by @ethomson in https://github.com/libgit2/libgit2/pull/6073
+* Handle long paths when querying attributes by @ethomson in https://github.com/libgit2/libgit2/pull/6075
+
+## Code cleanups
+* notes: use a buffer internally by @ethomson in https://github.com/libgit2/libgit2/pull/6047
+* Fix coding style for pointer by @punkymaniac in https://github.com/libgit2/libgit2/pull/6045
+* Use __typeof__ GNUC keyword for ISO C compatibility by @duncanthomson in https://github.com/libgit2/libgit2/pull/6041
+* Discover libssh2 without pkg-config by @stac47 in https://github.com/libgit2/libgit2/pull/6053
+* Longpath filter bug by @lrm29 in https://github.com/libgit2/libgit2/pull/6055
+* Add test to ensure empty proxy env behaves like unset env by @sathieu in https://github.com/libgit2/libgit2/pull/6052
+* Stdint header condition has been reverted. by @lolgear in https://github.com/libgit2/libgit2/pull/6020
+* buf: `common_prefix` takes a string array by @ethomson in https://github.com/libgit2/libgit2/pull/6077
+* oidarray: introduce `git_oidarray_dispose` by @ethomson in https://github.com/libgit2/libgit2/pull/6076
+* examples: Free the git_config and git_config_entry after use by @257 in https://github.com/libgit2/libgit2/pull/6071
+
+## CI Improvements
+* ci: pull libssh2 from www.libssh2.org by @ethomson in https://github.com/libgit2/libgit2/pull/6064
+
+## Documentation changes
+* Update README.md by @shijinglu in https://github.com/libgit2/libgit2/pull/6050
+
+## New Contributors
+* @basile-henry made their first contribution in https://github.com/libgit2/libgit2/pull/6043
+* @duncanthomson made their first contribution in https://github.com/libgit2/libgit2/pull/6041
+* @stac47 made their first contribution in https://github.com/libgit2/libgit2/pull/6053
+* @shijinglu made their first contribution in https://github.com/libgit2/libgit2/pull/6050
+* @ccstolley made their first contribution in https://github.com/libgit2/libgit2/pull/6060
+* @sathieu made their first contribution in https://github.com/libgit2/libgit2/pull/6052
+* @257 made their first contribution in https://github.com/libgit2/libgit2/pull/6071
+
+**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.2.0...v1.3.0
+
+---------------------------------------------------------------------
+
+v1.2
+-----
+
+This is release v1.2.0, "Absacker".  This release includes many new features: in particular, support for commit graphs, multi-pack indexes, and `core.longpaths` support.
+
+This is meant to be the final minor release in the v1 lineage.  v2.0 will be the next major release and will remove deprecated APIs and may include breaking changes.
+
+## Deprecated APIs
+
+* revspec: rename git_revparse_mode_t to git_revspec_t by @ethomson in https://github.com/libgit2/libgit2/pull/5786
+* tree: deprecate `git_treebuilder_write_with_buffer` by @ethomson in https://github.com/libgit2/libgit2/pull/5815
+* Deprecate `is_valid_name` functions; replace with `name_is_valid` functions by @ethomson in https://github.com/libgit2/libgit2/pull/5659
+* filter: stop taking git_buf as user input by @ethomson in https://github.com/libgit2/libgit2/pull/5859
+* remote: introduce remote_ready_cb, deprecate resolve_url callback by @ethomson in https://github.com/libgit2/libgit2/pull/6012
+* Introduce `create_commit_cb`, deprecate `signing_cb` by @ethomson in https://github.com/libgit2/libgit2/pull/6016
+* filter: filter drivers stop taking git_buf as user input by @ethomson in https://github.com/libgit2/libgit2/pull/6011
+* buf: deprecate public git_buf writing functions by @ethomson in https://github.com/libgit2/libgit2/pull/6017
+
+## New features
+
+* winhttp: support optional client cert by @ianhattendorf in https://github.com/libgit2/libgit2/pull/5384
+* Add support for additional SSH hostkey types. by @arroz in https://github.com/libgit2/libgit2/pull/5750
+* Handle ipv6 addresses by @ethomson in https://github.com/libgit2/libgit2/pull/5741
+* zlib: Add support for building with Chromium's zlib implementation by @lhchavez in https://github.com/libgit2/libgit2/pull/5748
+* commit-graph: Introduce a parser for commit-graph files by @lhchavez in https://github.com/libgit2/libgit2/pull/5762
+* patch: add owner accessor by @KOLANICH in https://github.com/libgit2/libgit2/pull/5731
+* commit-graph: Support lookups of entries in a commit-graph by @lhchavez in https://github.com/libgit2/libgit2/pull/5763
+* commit-graph: Introduce `git_commit_graph_needs_refresh()` by @lhchavez in https://github.com/libgit2/libgit2/pull/5764
+* Working directory path validation by @ethomson in https://github.com/libgit2/libgit2/pull/5823
+* Support `core.longpaths` on Windows by @ethomson in https://github.com/libgit2/libgit2/pull/5857
+* git_reference_create_matching: Treat all-zero OID as "must be absent" by @novalis in https://github.com/libgit2/libgit2/pull/5842
+* diff:add option to ignore blank line changes by @yuuri in https://github.com/libgit2/libgit2/pull/5853
+* [Submodule] Git submodule dup by @lolgear in https://github.com/libgit2/libgit2/pull/5890
+* commit-graph: Use the commit-graph in revwalks by @lhchavez in https://github.com/libgit2/libgit2/pull/5765
+* commit-graph: Introduce `git_commit_list_generation_cmp` by @lhchavez in https://github.com/libgit2/libgit2/pull/5766
+* graph: Create `git_graph_reachable_from_any()` by @lhchavez in https://github.com/libgit2/libgit2/pull/5767
+* Support reading attributes from a specific commit by @ethomson in https://github.com/libgit2/libgit2/pull/5952
+* [Branch] Branch upstream with format by @lolgear in https://github.com/libgit2/libgit2/pull/5861
+* Dynamically load OpenSSL (optionally) by @ethomson in https://github.com/libgit2/libgit2/pull/5974
+* Set refs/remotes/origin/HEAD to default branch when branch is specified by @A-Ovchinnikov-mx in https://github.com/libgit2/libgit2/pull/6010
+* midx: Add a way to write multi-pack-index files by @lhchavez in https://github.com/libgit2/libgit2/pull/5404
+* Use error code GIT_EAUTH for authentication failures by @josharian in https://github.com/libgit2/libgit2/pull/5395
+* midx: Introduce git_odb_write_multi_pack_index() by @lhchavez in https://github.com/libgit2/libgit2/pull/5405
+* Checkout dry-run by @J0Nes90 in https://github.com/libgit2/libgit2/pull/5841
+* mbedTLS: Fix setting certificate directory by @mikezackles in https://github.com/libgit2/libgit2/pull/6004
+* remote: introduce remote_ready_cb, deprecate resolve_url callback by @ethomson in https://github.com/libgit2/libgit2/pull/6012
+* Introduce `create_commit_cb`, deprecate `signing_cb` by @ethomson in https://github.com/libgit2/libgit2/pull/6016
+* commit-graph: Add a way to write commit-graph files by @lhchavez in https://github.com/libgit2/libgit2/pull/5778
+
+## Bug fixes
+
+* Define `git___load` when building with `-DTHREADSAFE=OFF` by @lhchavez in https://github.com/libgit2/libgit2/pull/5664
+* Make the Windows leak detection more robust by @lhchavez in https://github.com/libgit2/libgit2/pull/5661
+* Refactor "global" state by @ethomson in https://github.com/libgit2/libgit2/pull/5546
+* threadstate: rename tlsdata when building w/o threads by @ethomson in https://github.com/libgit2/libgit2/pull/5668
+* Include `${MBEDTLS_INCLUDE_DIR}` when compiling `crypt_mbedtls.c` by @staticfloat in https://github.com/libgit2/libgit2/pull/5685
+* Fix the `-DTHREADSAFE=OFF` build by @lhchavez in https://github.com/libgit2/libgit2/pull/5690
+* Add missing worktree_dir check and test case by @rbmclean in https://github.com/libgit2/libgit2/pull/5692
+* msvc crtdbg -> win32 leakcheck by @ethomson in https://github.com/libgit2/libgit2/pull/5580
+* Introduce GIT_ASSERT macros by @ethomson in https://github.com/libgit2/libgit2/pull/5327
+* Also add the raw hostkey to `git_cert_hostkey` by @lhchavez in https://github.com/libgit2/libgit2/pull/5704
+* Make the odb race-free by @lhchavez in https://github.com/libgit2/libgit2/pull/5595
+* Make the pack and mwindow implementations data-race-free by @lhchavez in https://github.com/libgit2/libgit2/pull/5593
+* Thread-free implementation by @ethomson in https://github.com/libgit2/libgit2/pull/5719
+* Thread-local storage: a generic internal library (with no allocations) by @ethomson in https://github.com/libgit2/libgit2/pull/5720
+* Friendlier getting started in the lack of git_libgit2_init by @ethomson in https://github.com/libgit2/libgit2/pull/5578
+* Make git__strntol64() ~70%* faster by @lhchavez in https://github.com/libgit2/libgit2/pull/5735
+* Cache the parsed submodule config when diffing by @lhchavez in https://github.com/libgit2/libgit2/pull/5727
+* pack: continue zlib while we can make progress by @ethomson in https://github.com/libgit2/libgit2/pull/5740
+* Avoid using `__builtin_mul_overflow` with the clang+32-bit combo by @lhchavez in https://github.com/libgit2/libgit2/pull/5742
+* repository: use intptr_t's in the config map cache by @ethomson in https://github.com/libgit2/libgit2/pull/5746
+* Build with NO_MMAP by @0xdky in https://github.com/libgit2/libgit2/pull/5583
+* Add documentation for git_blob_filter_options.version by @JoshuaS3 in https://github.com/libgit2/libgit2/pull/5759
+* blob: fix name of `GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD` by @ethomson in https://github.com/libgit2/libgit2/pull/5760
+* Cope with empty default branch by @ethomson in https://github.com/libgit2/libgit2/pull/5770
+* README: instructions for using libgit2 without compiling by @ethomson in https://github.com/libgit2/libgit2/pull/5772
+* Use `p_pwrite`/`p_pread` consistently throughout the codebase by @lhchavez in https://github.com/libgit2/libgit2/pull/5769
+* midx: Fix a bug in `git_midx_needs_refresh()` by @lhchavez in https://github.com/libgit2/libgit2/pull/5768
+* mwindow: Fix a bug in the LRU window finding code by @lhchavez in https://github.com/libgit2/libgit2/pull/5783
+* refdb_fs: Check git_sortedcache wlock/rlock errors by @mamapanda in https://github.com/libgit2/libgit2/pull/5800
+* index: Check git_vector_dup error in write_entries by @mamapanda in https://github.com/libgit2/libgit2/pull/5801
+* Fix documentation formating on repository.h by @punkymaniac in https://github.com/libgit2/libgit2/pull/5806
+* include: fix typos in comments by @tniessen in https://github.com/libgit2/libgit2/pull/5805
+* Fix some typos by @aaronfranke in https://github.com/libgit2/libgit2/pull/5797
+* Check git_signature_dup failure by @mamapanda in https://github.com/libgit2/libgit2/pull/5817
+* merge: Check insert_head_ids error in create_virtual_base by @mamapanda in https://github.com/libgit2/libgit2/pull/5818
+* winhttp: skip certificate check if unable to send request by @ianhattendorf in https://github.com/libgit2/libgit2/pull/5814
+* Default to GIT_BRANCH_DEFAULT if init.defaultBranch is empty string by @ianhattendorf in https://github.com/libgit2/libgit2/pull/5832
+* Fix diff_entrycount -> diff_num_deltas doc typo by @mjsir911 in https://github.com/libgit2/libgit2/pull/5838
+* repo: specify init.defaultbranch is meant to be a branch name by @carlosmn in https://github.com/libgit2/libgit2/pull/5835
+* repo: remove an inappropriate use of PASSTHROUGH by @carlosmn in https://github.com/libgit2/libgit2/pull/5834
+* src: fix typos in header files by @tniessen in https://github.com/libgit2/libgit2/pull/5843
+* test: clean up memory leaks by @ethomson in https://github.com/libgit2/libgit2/pull/5858
+* buf: remove unnecessary buf_text namespace by @ethomson in https://github.com/libgit2/libgit2/pull/5860
+* Fix bug in git_diff_find_similar. by @staktrace in https://github.com/libgit2/libgit2/pull/5839
+* Fix issues with Proxy Authentication after httpclient refactor by @implausible in https://github.com/libgit2/libgit2/pull/5852
+* tests: clean up memory leak, fail on leak for win32 by @ethomson in https://github.com/libgit2/libgit2/pull/5892
+* Tolerate readlink size less than st_size by @dtolnay in https://github.com/libgit2/libgit2/pull/5900
+* Define WINHTTP_NO_CLIENT_CERT_CONTEXT if needed by @jacquesg in https://github.com/libgit2/libgit2/pull/5929
+* Update from regex to pcre licensing information in docs/contributing.md by @boretrk in https://github.com/libgit2/libgit2/pull/5916
+* Consider files executable only if the user can execute them by @novalis in https://github.com/libgit2/libgit2/pull/5915
+* git__timer: Limit ITimer usage to AmigaOS4 by @boretrk in https://github.com/libgit2/libgit2/pull/5936
+* Fix memory leak in git_smart__connect by @punkymaniac in https://github.com/libgit2/libgit2/pull/5908
+* config: fix included configs not refreshed more than once by @Batchyx in https://github.com/libgit2/libgit2/pull/5926
+* Fix wrong time_t used in function by @NattyNarwhal in https://github.com/libgit2/libgit2/pull/5938
+* fix check for ignoring of negate rules by @palmin in https://github.com/libgit2/libgit2/pull/5824
+* Make `FIND_PACKAGE(PythonInterp)` prefer `python3` by @lhchavez in https://github.com/libgit2/libgit2/pull/5913
+* git__timer: Allow compilation on systems without CLOCK_MONOTONIC by @boretrk in https://github.com/libgit2/libgit2/pull/5945
+* stdintification: use int64_t and INT64_C instead of long long by @NattyNarwhal in https://github.com/libgit2/libgit2/pull/5941
+* Optional stricter allocation checking (for `malloc(0)` cases) by @ethomson in https://github.com/libgit2/libgit2/pull/5951
+* Variadic arguments aren't in C89 by @NattyNarwhal in https://github.com/libgit2/libgit2/pull/5948
+* Fix typo in general.c by @Crayon2000 in https://github.com/libgit2/libgit2/pull/5954
+* common.h: use inline when compiling for C99 and later by @boretrk in https://github.com/libgit2/libgit2/pull/5953
+* Fix one memory leak in master by @lhchavez in https://github.com/libgit2/libgit2/pull/5957
+* tests: reset odb backend priority by @ethomson in https://github.com/libgit2/libgit2/pull/5961
+* cmake: extended futimens checking on macOS by @ethomson in https://github.com/libgit2/libgit2/pull/5962
+* amiga: use ';' as path list separator on AmigaOS by @boretrk in https://github.com/libgit2/libgit2/pull/5978
+* Respect the force flag on refspecs in git_remote_fetch by @alexjg in https://github.com/libgit2/libgit2/pull/5854
+* Fix LIBGIT2_FILENAME not being passed to the resource compiler by @jairbubbles in https://github.com/libgit2/libgit2/pull/5994
+* sha1dc: remove conditional for <sys/types.h> by @boretrk in https://github.com/libgit2/libgit2/pull/5997
+* openssl: don't fail when we can't customize allocators by @ethomson in https://github.com/libgit2/libgit2/pull/5999
+* C11 warnings by @boretrk in https://github.com/libgit2/libgit2/pull/6005
+* open: input validation for empty segments in path by @boretrk in https://github.com/libgit2/libgit2/pull/5950
+* Introduce GIT_WARN_UNUSED_RESULT by @lhchavez in https://github.com/libgit2/libgit2/pull/5802
+* GCC C11 warnings by @boretrk in https://github.com/libgit2/libgit2/pull/6006
+* array: check dereference from void * type by @boretrk in https://github.com/libgit2/libgit2/pull/6007
+* Homogenize semantics for atomic-related functions by @lhchavez in https://github.com/libgit2/libgit2/pull/5747
+* git_array_alloc: return objects of correct type by @boretrk in https://github.com/libgit2/libgit2/pull/6008
+* CMake. hash sha1 header has been added. by @lolgear in https://github.com/libgit2/libgit2/pull/6013
+* tests: change comments to c89 style by @boretrk in https://github.com/libgit2/libgit2/pull/6015
+* Set Host Header to match CONNECT authority target by @lollipopman in https://github.com/libgit2/libgit2/pull/6022
+* Fix worktree iteration when repository has no common directory by @kcsaul in https://github.com/libgit2/libgit2/pull/5943
+
+## Documentation improvements
+
+* Update README.md for additional Delphi bindings by @todaysoftware in https://github.com/libgit2/libgit2/pull/5831
+* Fix documentation formatting by @punkymaniac in https://github.com/libgit2/libgit2/pull/5850
+* docs: fix incorrect comment marker by @tiennou in https://github.com/libgit2/libgit2/pull/5897
+* Patch documentation by @punkymaniac in https://github.com/libgit2/libgit2/pull/5903
+* Fix misleading doc for `git_index_find` by @arxanas in https://github.com/libgit2/libgit2/pull/5910
+* docs: stop mentioning libgit2's "master" branch by @Batchyx in https://github.com/libgit2/libgit2/pull/5925
+* docs: fix some missing includes that cause Docurium to error out by @tiennou in https://github.com/libgit2/libgit2/pull/5917
+* Patch documentation by @punkymaniac in https://github.com/libgit2/libgit2/pull/5940
+
+## Development improvements
+
+* WIP: .devcontainer: settings for a codespace workflow by @ethomson in https://github.com/libgit2/libgit2/pull/5508
+
+## CI Improvements
+
+* Add a ThreadSanitizer build by @lhchavez in https://github.com/libgit2/libgit2/pull/5597
+* ci: more GitHub Actions by @ethomson in https://github.com/libgit2/libgit2/pull/5706
+* ci: run coverity in the nightly builds by @ethomson in https://github.com/libgit2/libgit2/pull/5707
+* ci: only report main branch in README status by @ethomson in https://github.com/libgit2/libgit2/pull/5708
+* Fix the `ENABLE_WERROR=ON` build in Groovy Gorilla (gcc 10.2) by @lhchavez in https://github.com/libgit2/libgit2/pull/5715
+* Re-enable the RC4 test by @carlosmn in https://github.com/libgit2/libgit2/pull/4418
+* ci: run codeql by @ethomson in https://github.com/libgit2/libgit2/pull/5709
+* github-actions: Also rename the main branch here by @lhchavez in https://github.com/libgit2/libgit2/pull/5771
+* ci: don't use ninja on macOS by @ethomson in https://github.com/libgit2/libgit2/pull/5780
+* ci: use GitHub for storing mingw-w64 build dependency by @ethomson in https://github.com/libgit2/libgit2/pull/5855
+* docker: remove the entrypoint by @ethomson in https://github.com/libgit2/libgit2/pull/5980
+* http: don't require a password by @ethomson in https://github.com/libgit2/libgit2/pull/5972
+* ci: update nightly to use source path by @ethomson in https://github.com/libgit2/libgit2/pull/5989
+* ci: add centos 7 and centos 8 by @ethomson in https://github.com/libgit2/libgit2/pull/5992
+* ci: update centos builds by @ethomson in https://github.com/libgit2/libgit2/pull/5995
+* ci: tag new containers with the latest tag by @ethomson in https://github.com/libgit2/libgit2/pull/6000
+
+## Dependency updates
+
+* ntlm: [ntlmclient](https://github.com/ethomson/ntlmclient) is now v0.9.1
+
+**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.1.0...v1.2.0
+
+---------------------------------------------------------------------
+
 v1.1
 ----
 
@@ -87,6 +319,8 @@ This is a bugfix release with the following changes:
   has been fixed.  Previously, fetching from servers like Gerrit, that
   sent large data packets, would error.
 
+---------------------------------------------------------------------
+
 v1.0
 ----
 
@@ -490,6 +724,9 @@ with v0.28.0.
   The breaking change is that the `username` member of the underlying struct
   is now hidden, and a new `git_cred_get_username` function has been provided.
 
+* Some errors of class `GIT_ERROR_NET` now have class `GIT_ERROR_HTTP`.
+  Most authentication failures now have error code `GIT_EAUTH` instead of `GIT_ERROR`.
+
 ### Breaking CMake configuration changes
 
 * The CMake option to use a system http-parser library, instead of the
@@ -563,6 +800,8 @@ release:
 * Tyler Ang-Wanek
 * Tyler Wanek
 
+---------------------------------------------------------------------
+
 v0.28
 -----
 
@@ -711,6 +950,8 @@ v0.28
   out such files is not allowed as this can make a Git implementation write
   outside of the repository and bypass the fsck checks for CVE-2018-11235.
 
+---------------------------------------------------------------------
+
 v0.27
 ---------
 
@@ -827,6 +1068,8 @@ v0.27
   `git_odb_backend` interface have changed their signatures to allow providing
   the object's size and type to the caller.
 
+---------------------------------------------------------------------
+    
 v0.26
 -----
 
@@ -1071,6 +1314,8 @@ v0.25
   to provide the name of a merge driver to be used to handle files changed
   during a merge.
 
+---------------------------------------------------------------------
+
 v0.24
 -------
 
@@ -1186,6 +1431,8 @@ v0.24
 * `git_remote_connect()` now takes a `custom_headers` argument to set
   the extra HTTP header fields to send.
 
+---------------------------------------------------------------------
+
 v0.23
 ------
 
@@ -1485,6 +1732,8 @@ v0.23
 * It is no longer allowed to call `git_buf_grow()` on buffers
   borrowing the memory they point to.
 
+---------------------------------------------------------------------
+
 v0.22
 ------
 
index d5188f0bc0c1f990d9d3857cb3efe378c0af21e0..b8b94d69ca867caf7cdb756f9856bd96434451ac 100644 (file)
@@ -172,7 +172,7 @@ tags:
  *
  * @param s String to froznicate
  * @return A newly allocated string or `NULL` in case an error occurred.
- * /
+ */
 char *froznicate(const char *s);
 ```
 
index 21e42b1d92f1c8f415a09258ed0aa42189172b67..f3e559c9d812a64d78aab63df6bface5932dfede 100644 (file)
@@ -18,7 +18,7 @@ The bundled dependencies in the `deps` directories are governed
 by the following licenses:
 
 - http-parser is licensed under [MIT license](../deps/http-parser/COPYING)
-- regex is governed by [LGPL v2.1+ license](../deps/regex/COPYING)
+- pcre is governed by [BSD license](../deps/pcre/LICENCE)
 - winhttp is governed by [LGPL v2.1+](../deps/winhttp/COPYING.LGPL) and [GPL v2 with linking exception](../deps/winhttp/COPYING.GPL)
 - zlib is governed by [zlib license](../deps/zlib/COPYING)
 
@@ -35,7 +35,7 @@ easily accessible permanent record of the conversation.
 
 ## Libgit2 Versions
 
-The `master` branch is the main branch where development happens.
+The `main` branch is the main branch where development happens.
 Releases are tagged
 (e.g. [v0.21.0](https://github.com/libgit2/libgit2/releases/tag/v0.21.0) )
 and when a critical bug fix needs to be backported, it will be done on a
@@ -51,7 +51,7 @@ commit SHA
 Using [`git describe`](http://git-scm.com/docs/git-describe) is a
 great way to tell us what version you're working with.
 
-If you're not running against the latest `master` branch version,
+If you're not running against the latest `main` branch version,
 please compile and test against that to avoid re-reporting an issue that's
 already been fixed.
 
@@ -68,11 +68,11 @@ flow](https://guides.github.com/introduction/flow/index.html), where
 contributors fork the [libgit2 repository](https://github.com/libgit2/libgit2),
 make their changes on branch, and submit a
 [Pull Request](https://help.github.com/articles/using-pull-requests)
-(a.k.a. "PR").  Pull requests should usually be targeted at the `master`
+(a.k.a. "PR").  Pull requests should usually be targeted at the `main`
 branch.
 
 Life will be a lot easier for you (and us) if you follow this pattern
-(i.e. fork, named branch, submit PR).  If you use your fork's `master`
+(i.e. fork, named branch, submit PR).  If you use your fork's `main`
 branch directly, things can get messy.
 
 Please include a nice description of your changes when you submit your PR;
index 22b35ede7dbe6772f6ccf60ec2fb6e93a8b1036d..3200c4449e47f9eeedadb8135c2b6c22012fd137 100644 (file)
@@ -1,6 +1,6 @@
 # Releasing the library
 
-We have three kinds of releases: "full" releases, maintenance releases and security releases. Full ones release the state of the `master` branch whereas maintenance releases provide bugfixes building on top of the currently released series. Security releases are also for the current series but only contain security fixes on top of the previous release.
+We have three kinds of releases: "full" releases, maintenance releases and security releases. Full ones release the state of the `main` branch whereas maintenance releases provide bugfixes building on top of the currently released series. Security releases are also for the current series but only contain security fixes on top of the previous release.
 
 ## Full release
 
@@ -40,7 +40,7 @@ followed by the three sections in the changelog. For release candidates we can a
 
 During the freeze, and certainly after the first release candidate, any bindings the core team work with should be updated in order to discover any issues that might come up with the multitude of approaches to memory management, embedding or linking.
 
-Create a branch `maint/v0.X` at the current state of `master` after you've created the tag. This will be used for maintenance releases and lets our dependents track the latest state of the series.
+Create a branch `maint/v0.X` at the current state of `main` after you've created the tag. This will be used for maintenance releases and lets our dependents track the latest state of the series.
 
 ## Maintenance release
 
@@ -76,7 +76,7 @@ We use docurium to generate our documentation. It is a tool written in ruby whic
 
     gem install docurium
 
-and run it against our description file with the tip of master checked out.
+and run it against our description file with the tip of `main` checked out.
 
     cm doc api.docurium
 
diff --git a/docs/win32-longpaths.md b/docs/win32-longpaths.md
new file mode 100644 (file)
index 0000000..a18152f
--- /dev/null
@@ -0,0 +1,36 @@
+core.longpaths support
+======================
+
+Historically, Windows has limited absolute path lengths to `MAX_PATH`
+(260) characters.
+
+Unfortunately, 260 characters is a punishing small maximum.  This is
+especially true for developers where dependencies may have dependencies
+in a folder, each dependency themselves having dependencies in a
+sub-folder, ad (seemingly) infinitum.
+
+So although the Windows APIs _by default_ honor this 260 character
+maximum, you can get around this by using separate APIs.  Git honors a
+`core.longpaths` configuration option that allows some paths on Windows
+to exceed these 260 character limits.
+
+And because they've gone and done it, that means that libgit2 has to
+honor this value, too.
+
+Since `core.longpaths` is a _configuration option_ that means that we
+need to be able to resolve a configuration - including in _the repository
+itself_ in order to know whether long paths should be supported.
+
+Therefore, in libgit2, `core.longpaths` affects paths in working
+directories _only_.  Paths to the repository, and to items inside the
+`.git` folder, must be no longer than 260 characters.
+
+This definition is required to avoid a paradoxical setting: if you
+had a repository in a folder that was 280 characters long, how would
+you know whether `core.longpaths` support should be enabled?  Even if
+`core.longpaths` was set to true in a system configuration file, the
+repository itself may set `core.longpaths` to false in _its_ configuration
+file, which you could only read if `core.longpaths` were set to true.
+
+Thus, `core.longpaths` must _only_ apply to working directory items,
+and cannot apply to the `.git` folder or its contents.
index 49350fc0f0ac2675492764c329d64259acb0b552..954c97b17d170397d2c9f8e743e096e06e64f9e5 100644 (file)
@@ -54,7 +54,7 @@ int lg2_blame(git_repository *repo, int argc, char *argv[])
         */
        if (o.commitspec) {
                check_lg2(git_revparse(&revspec, repo, o.commitspec), "Couldn't parse commit spec", NULL);
-               if (revspec.flags & GIT_REVPARSE_SINGLE) {
+               if (revspec.flags & GIT_REVSPEC_SINGLE) {
                        git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.from));
                        git_object_free(revspec.from);
                } else {
index 204b58d88251e0138706683ac60c7f146147fbae..ac7b7422d7b296320d8709e3fdc328bff2e70a8f 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "common.h"
 
-/* Define the printf format specifer to use for size_t output */
+/* Define the printf format specifier to use for size_t output */
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #      define PRIuZ "Iu"
 #      define PRIxZ "Ix"
index 0126568aba8cbf18a9baf62ad4bb40f6831e7a0f..f86e92c3574c7f46d8335c714a35859b4e24fdcd 100644 (file)
@@ -36,7 +36,7 @@
 #endif
 
 #ifndef PRIuZ
-/* Define the printf format specifer to use for size_t output */
+/* Define the printf format specifier to use for size_t output */
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #      define PRIuZ "Iu"
 #else
index f7fa70e4d700efe1fc83a0df52d01516e0729ad9..6e14ce8c8669821c920ff37db79ad2db9449b5d7 100644 (file)
@@ -26,6 +26,10 @@ static int config_get(git_config *cfg, const char *key)
        }
 
        puts(entry->value);
+
+       /* Free the git_config_entry after use with `git_config_entry_free()`. */
+       git_config_entry_free(entry);
+
        return 0;
 }
 
@@ -57,6 +61,11 @@ int lg2_config(git_repository *repo, int argc, char **argv)
                error = 1;
        }
 
+       /**
+        * The configuration file must be freed once it's no longer
+        * being used by the user.
+       */
+       git_config_free(cfg);
 out:
        return error;
 }
index 1622ff8b008d93a09127a9aa148e55521602439a..2127ec0e1ea73e92748091e0e3a507abb6d8003b 100644 (file)
@@ -154,11 +154,6 @@ static void oid_parsing(git_oid *oid)
        printf("\n*Raw to Hex*\n");
        out[GIT_OID_HEXSZ] = '\0';
 
-       /**
-        * If you have a oid, you can easily get the hex value of the SHA as well.
-        */
-       git_oid_fmt(out, oid);
-
        /**
         * If you have a oid, you can easily get the hex value of the SHA as well.
         */
@@ -713,7 +708,7 @@ static void reference_listing(git_repository *repo)
 /**
  * ### Config Files
  *
- * The [config API][config] allows you to list and updatee config values
+ * The [config API][config] allows you to list and update config values
  * in any of the accessible config file locations (system, global, local).
  *
  * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config
index ee18df542256106b2f84049b585c3e63d58a2a15..9060f3f3ea2edb74a07ba9da9df570327a8f67de 100644 (file)
@@ -245,7 +245,7 @@ static int add_revision(struct log_state *s, const char *revstr)
        }
 
        if (*revstr == '^') {
-               revs.flags = GIT_REVPARSE_SINGLE;
+               revs.flags = GIT_REVSPEC_SINGLE;
                hide = !hide;
 
                if (git_revparse_single(&revs.from, s->repo, revstr + 1) < 0)
@@ -253,12 +253,12 @@ static int add_revision(struct log_state *s, const char *revstr)
        } else if (git_revparse(&revs, s->repo, revstr) < 0)
                return -1;
 
-       if ((revs.flags & GIT_REVPARSE_SINGLE) != 0)
+       if ((revs.flags & GIT_REVSPEC_SINGLE) != 0)
                push_rev(s, revs.from, hide);
        else {
                push_rev(s, revs.to, hide);
 
-               if ((revs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
+               if ((revs.flags & GIT_REVSPEC_MERGE_BASE) != 0) {
                        git_oid base;
                        check_lg2(git_merge_base(&base, s->repo,
                                git_object_id(revs.from), git_object_id(revs.to)),
index 75fb19e70794290f96565d3c4be300daf3b5518e..d10f166900ef706e69c31db97b2ae42f26ceb642 100644 (file)
@@ -73,7 +73,7 @@ static int push_range(git_repository *repo, git_revwalk *walk, const char *range
        if ((error = git_revparse(&revspec, repo, range)))
                return error;
 
-       if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
+       if (revspec.flags & GIT_REVSPEC_MERGE_BASE) {
                /* TODO: support "<commit>...<commit>" */
                return GIT_EINVALIDSPEC;
        }
index 7d6e9986f281a01281b62198af948d59d6114c7f..90258c10139756f4e07367fe212ba2b435c7562e 100644 (file)
@@ -69,17 +69,17 @@ static int parse_revision(git_repository *repo, struct parse_state *ps)
 
        check_lg2(git_revparse(&rs, repo, ps->spec), "Could not parse", ps->spec);
 
-       if ((rs.flags & GIT_REVPARSE_SINGLE) != 0) {
+       if ((rs.flags & GIT_REVSPEC_SINGLE) != 0) {
                git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
                printf("%s\n", str);
                git_object_free(rs.from);
        }
-       else if ((rs.flags & GIT_REVPARSE_RANGE) != 0) {
+       else if ((rs.flags & GIT_REVSPEC_RANGE) != 0) {
                git_oid_tostr(str, sizeof(str), git_object_id(rs.to));
                printf("%s\n", str);
                git_object_free(rs.to);
 
-               if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
+               if ((rs.flags & GIT_REVSPEC_MERGE_BASE) != 0) {
                        git_oid base;
                        check_lg2(git_merge_base(&base, repo,
                                                git_object_id(rs.from), git_object_id(rs.to)),
index 03d9c2bf9b2e32b7acdce6cdb916aaf4ad88d415..e4f71ae625fb94110316fae4f06184fd1f1fad16 100644 (file)
@@ -188,7 +188,7 @@ static void action_delete_tag(tag_state *state)
        git_object_free(obj);
 }
 
-static void action_create_lighweight_tag(tag_state *state)
+static void action_create_lightweight_tag(tag_state *state)
 {
        git_repository *repo = state->repo;
        struct tag_options *opts = state->opts;
@@ -260,7 +260,7 @@ static void parse_options(tag_action *action, struct tag_options *opts, int argc
                                print_usage();
 
                        if (*action != &action_create_tag)
-                               *action = &action_create_lighweight_tag;
+                               *action = &action_create_lightweight_tag;
                } else if (!strcmp(curr, "-n")) {
                        opts->num_lines = 1;
                        *action = &action_list_tags;
diff --git a/fuzzers/commit_graph_fuzzer.c b/fuzzers/commit_graph_fuzzer.c
new file mode 100644 (file)
index 0000000..b41816e
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * libgit2 commit-graph fuzzer target.
+ *
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include <stdio.h>
+
+#include "git2.h"
+
+#include "buffer.h"
+#include "common.h"
+#include "futils.h"
+#include "hash.h"
+#include "commit_graph.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+       GIT_UNUSED(argc);
+       GIT_UNUSED(argv);
+
+       if (git_libgit2_init() < 0) {
+               fprintf(stderr, "Failed to initialize libgit2\n");
+               abort();
+       }
+       return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+       git_commit_graph_file file = {{0}};
+       git_commit_graph_entry e;
+       git_buf commit_graph_buf = GIT_BUF_INIT;
+       git_oid oid = {{0}};
+       bool append_hash = false;
+
+       if (size < 4)
+               return 0;
+
+       /*
+        * If the first byte in the stream has the high bit set, append the
+        * SHA1 hash so that the file is somewhat valid.
+        */
+       append_hash = *data & 0x80;
+       /* Keep a 4-byte alignment to avoid unaligned accesses. */
+       data += 4;
+       size -= 4;
+
+       if (append_hash) {
+               if (git_buf_init(&commit_graph_buf, size + sizeof(oid)) < 0)
+                       goto cleanup;
+               if (git_hash_buf(&oid, data, size) < 0) {
+                       fprintf(stderr, "Failed to compute the SHA1 hash\n");
+                       abort();
+               }
+               memcpy(commit_graph_buf.ptr, data, size);
+               memcpy(commit_graph_buf.ptr + size, &oid, sizeof(oid));
+       } else {
+               git_buf_attach_notowned(&commit_graph_buf, (char *)data, size);
+       }
+
+       if (git_commit_graph_file_parse(
+                           &file,
+                           (const unsigned char *)git_buf_cstr(&commit_graph_buf),
+                           git_buf_len(&commit_graph_buf))
+           < 0)
+               goto cleanup;
+
+       /* Search for any oid, just to exercise that codepath. */
+       if (git_commit_graph_entry_find(&e, &file, &oid, GIT_OID_HEXSZ) < 0)
+               goto cleanup;
+
+cleanup:
+       git_commit_graph_file_close(&file);
+       git_buf_dispose(&commit_graph_buf);
+       return 0;
+}
diff --git a/fuzzers/corpora/commit_graph/005682ce1cb5b20c20fccf4be5dbd47ca399e53e b/fuzzers/corpora/commit_graph/005682ce1cb5b20c20fccf4be5dbd47ca399e53e
new file mode 100644 (file)
index 0000000..15d0d28
Binary files /dev/null and b/fuzzers/corpora/commit_graph/005682ce1cb5b20c20fccf4be5dbd47ca399e53e differ
diff --git a/fuzzers/corpora/commit_graph/00574fc29fd1323e93d18d625cde80d3ea20e8cc b/fuzzers/corpora/commit_graph/00574fc29fd1323e93d18d625cde80d3ea20e8cc
new file mode 100644 (file)
index 0000000..4eabd00
Binary files /dev/null and b/fuzzers/corpora/commit_graph/00574fc29fd1323e93d18d625cde80d3ea20e8cc differ
diff --git a/fuzzers/corpora/commit_graph/00916ec21ddbd3c622bde6e4dc824250176b9e88 b/fuzzers/corpora/commit_graph/00916ec21ddbd3c622bde6e4dc824250176b9e88
new file mode 100644 (file)
index 0000000..d069fb5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/00916ec21ddbd3c622bde6e4dc824250176b9e88 differ
diff --git a/fuzzers/corpora/commit_graph/00b6dde4b8d5e68a5ec40d88c39134cf2f1f8bc3 b/fuzzers/corpora/commit_graph/00b6dde4b8d5e68a5ec40d88c39134cf2f1f8bc3
new file mode 100644 (file)
index 0000000..98f2d0e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/00b6dde4b8d5e68a5ec40d88c39134cf2f1f8bc3 differ
diff --git a/fuzzers/corpora/commit_graph/020f0e77e42d8b3810019050f4c5ceadd205b37c b/fuzzers/corpora/commit_graph/020f0e77e42d8b3810019050f4c5ceadd205b37c
new file mode 100644 (file)
index 0000000..d09327d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/020f0e77e42d8b3810019050f4c5ceadd205b37c differ
diff --git a/fuzzers/corpora/commit_graph/02739c05abc1715fac1ce995b532e482abc8d4dc b/fuzzers/corpora/commit_graph/02739c05abc1715fac1ce995b532e482abc8d4dc
new file mode 100644 (file)
index 0000000..b9de08e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/02739c05abc1715fac1ce995b532e482abc8d4dc differ
diff --git a/fuzzers/corpora/commit_graph/02a276faa5dc8c7df5b82a57ab6cd195a13e4ae0 b/fuzzers/corpora/commit_graph/02a276faa5dc8c7df5b82a57ab6cd195a13e4ae0
new file mode 100644 (file)
index 0000000..891d3ef
Binary files /dev/null and b/fuzzers/corpora/commit_graph/02a276faa5dc8c7df5b82a57ab6cd195a13e4ae0 differ
diff --git a/fuzzers/corpora/commit_graph/02de15987d68a97db3d9fd964cfd785bcbd54d3a b/fuzzers/corpora/commit_graph/02de15987d68a97db3d9fd964cfd785bcbd54d3a
new file mode 100644 (file)
index 0000000..b8bd4ce
Binary files /dev/null and b/fuzzers/corpora/commit_graph/02de15987d68a97db3d9fd964cfd785bcbd54d3a differ
diff --git a/fuzzers/corpora/commit_graph/02e106f97a91b1d3aef4dd2d31368ae5077bd42b b/fuzzers/corpora/commit_graph/02e106f97a91b1d3aef4dd2d31368ae5077bd42b
new file mode 100644 (file)
index 0000000..f127739
Binary files /dev/null and b/fuzzers/corpora/commit_graph/02e106f97a91b1d3aef4dd2d31368ae5077bd42b differ
diff --git a/fuzzers/corpora/commit_graph/038555bcb4cc2daf764840f79ebce4023bdb7670 b/fuzzers/corpora/commit_graph/038555bcb4cc2daf764840f79ebce4023bdb7670
new file mode 100644 (file)
index 0000000..239f4e6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/038555bcb4cc2daf764840f79ebce4023bdb7670 differ
diff --git a/fuzzers/corpora/commit_graph/04c159a04b0732e04ac4c59ed3356860af8dffce b/fuzzers/corpora/commit_graph/04c159a04b0732e04ac4c59ed3356860af8dffce
new file mode 100644 (file)
index 0000000..856af0f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/04c159a04b0732e04ac4c59ed3356860af8dffce differ
diff --git a/fuzzers/corpora/commit_graph/0560ec993882ffbd8d46dcab0ed430089c4f2aa1 b/fuzzers/corpora/commit_graph/0560ec993882ffbd8d46dcab0ed430089c4f2aa1
new file mode 100644 (file)
index 0000000..a236d1a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0560ec993882ffbd8d46dcab0ed430089c4f2aa1 differ
diff --git a/fuzzers/corpora/commit_graph/059b3aab3fde6b4c9404aff83fed638596f594bb b/fuzzers/corpora/commit_graph/059b3aab3fde6b4c9404aff83fed638596f594bb
new file mode 100644 (file)
index 0000000..4900105
Binary files /dev/null and b/fuzzers/corpora/commit_graph/059b3aab3fde6b4c9404aff83fed638596f594bb differ
diff --git a/fuzzers/corpora/commit_graph/06168e726aa0260f520165be4ea0c88244831049 b/fuzzers/corpora/commit_graph/06168e726aa0260f520165be4ea0c88244831049
new file mode 100644 (file)
index 0000000..4c9e9df
Binary files /dev/null and b/fuzzers/corpora/commit_graph/06168e726aa0260f520165be4ea0c88244831049 differ
diff --git a/fuzzers/corpora/commit_graph/066d1ec700a526b97009cedd0305b6a47242faba b/fuzzers/corpora/commit_graph/066d1ec700a526b97009cedd0305b6a47242faba
new file mode 100644 (file)
index 0000000..f5b1761
Binary files /dev/null and b/fuzzers/corpora/commit_graph/066d1ec700a526b97009cedd0305b6a47242faba differ
diff --git a/fuzzers/corpora/commit_graph/086a5f8cbfa9f058b5c938a6eb724c9e4c5f84f3 b/fuzzers/corpora/commit_graph/086a5f8cbfa9f058b5c938a6eb724c9e4c5f84f3
new file mode 100644 (file)
index 0000000..aa9cdca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/086a5f8cbfa9f058b5c938a6eb724c9e4c5f84f3 differ
diff --git a/fuzzers/corpora/commit_graph/089313c698f3e351433e9a45af2ace1d85b9673e b/fuzzers/corpora/commit_graph/089313c698f3e351433e9a45af2ace1d85b9673e
new file mode 100644 (file)
index 0000000..14fd3bb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/089313c698f3e351433e9a45af2ace1d85b9673e differ
diff --git a/fuzzers/corpora/commit_graph/092eb973a771fa14cf0b567d65bd2c99130f543e b/fuzzers/corpora/commit_graph/092eb973a771fa14cf0b567d65bd2c99130f543e
new file mode 100644 (file)
index 0000000..3092a2b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/092eb973a771fa14cf0b567d65bd2c99130f543e differ
diff --git a/fuzzers/corpora/commit_graph/094b8cd1aa3e40b1f9ff83680892d52e246df0f8 b/fuzzers/corpora/commit_graph/094b8cd1aa3e40b1f9ff83680892d52e246df0f8
new file mode 100644 (file)
index 0000000..ed62ec9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/094b8cd1aa3e40b1f9ff83680892d52e246df0f8 differ
diff --git a/fuzzers/corpora/commit_graph/0ce990c9c2ec121b8c78ba2bdf84679e04c0bdae b/fuzzers/corpora/commit_graph/0ce990c9c2ec121b8c78ba2bdf84679e04c0bdae
new file mode 100644 (file)
index 0000000..d708b68
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0ce990c9c2ec121b8c78ba2bdf84679e04c0bdae differ
diff --git a/fuzzers/corpora/commit_graph/0dd0770c34fcf6b1f13219450190616d344db021 b/fuzzers/corpora/commit_graph/0dd0770c34fcf6b1f13219450190616d344db021
new file mode 100644 (file)
index 0000000..aea94b2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0dd0770c34fcf6b1f13219450190616d344db021 differ
diff --git a/fuzzers/corpora/commit_graph/0e2b2e6a32733b8a625bc7e812e2ea508d69a5e4 b/fuzzers/corpora/commit_graph/0e2b2e6a32733b8a625bc7e812e2ea508d69a5e4
new file mode 100644 (file)
index 0000000..58e8801
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0e2b2e6a32733b8a625bc7e812e2ea508d69a5e4 differ
diff --git a/fuzzers/corpora/commit_graph/0e8d0bd07c543d708aecaca377106492b7a74fa3 b/fuzzers/corpora/commit_graph/0e8d0bd07c543d708aecaca377106492b7a74fa3
new file mode 100644 (file)
index 0000000..98a9230
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0e8d0bd07c543d708aecaca377106492b7a74fa3 differ
diff --git a/fuzzers/corpora/commit_graph/0f0d16e1b8c8671dbe1074115c1d86aa9b359e7e b/fuzzers/corpora/commit_graph/0f0d16e1b8c8671dbe1074115c1d86aa9b359e7e
new file mode 100644 (file)
index 0000000..bc322de
Binary files /dev/null and b/fuzzers/corpora/commit_graph/0f0d16e1b8c8671dbe1074115c1d86aa9b359e7e differ
diff --git a/fuzzers/corpora/commit_graph/102ef78036de5a30927e7f751377b05441c41a08 b/fuzzers/corpora/commit_graph/102ef78036de5a30927e7f751377b05441c41a08
new file mode 100644 (file)
index 0000000..3b14c35
Binary files /dev/null and b/fuzzers/corpora/commit_graph/102ef78036de5a30927e7f751377b05441c41a08 differ
diff --git a/fuzzers/corpora/commit_graph/10494e7cc9cb8dff289c431d7560bcee0d1b14ed b/fuzzers/corpora/commit_graph/10494e7cc9cb8dff289c431d7560bcee0d1b14ed
new file mode 100644 (file)
index 0000000..293c49d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/10494e7cc9cb8dff289c431d7560bcee0d1b14ed differ
diff --git a/fuzzers/corpora/commit_graph/107b11d86381345f50aa19b8485477a870ff399f b/fuzzers/corpora/commit_graph/107b11d86381345f50aa19b8485477a870ff399f
new file mode 100644 (file)
index 0000000..53bb34e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/107b11d86381345f50aa19b8485477a870ff399f differ
diff --git a/fuzzers/corpora/commit_graph/10bb37e18fb3c0897dabacf9c464b4d324007dc3 b/fuzzers/corpora/commit_graph/10bb37e18fb3c0897dabacf9c464b4d324007dc3
new file mode 100644 (file)
index 0000000..e75a9c5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/10bb37e18fb3c0897dabacf9c464b4d324007dc3 differ
diff --git a/fuzzers/corpora/commit_graph/10ee715f64b08549c3e8261204276694728eb841 b/fuzzers/corpora/commit_graph/10ee715f64b08549c3e8261204276694728eb841
new file mode 100644 (file)
index 0000000..104eda6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/10ee715f64b08549c3e8261204276694728eb841 differ
diff --git a/fuzzers/corpora/commit_graph/123e4eeb7a731f48d06e336b4d29af717f8b6550 b/fuzzers/corpora/commit_graph/123e4eeb7a731f48d06e336b4d29af717f8b6550
new file mode 100644 (file)
index 0000000..22d1482
Binary files /dev/null and b/fuzzers/corpora/commit_graph/123e4eeb7a731f48d06e336b4d29af717f8b6550 differ
diff --git a/fuzzers/corpora/commit_graph/125a228afb923970e0a6d4412f7257ba998594a1 b/fuzzers/corpora/commit_graph/125a228afb923970e0a6d4412f7257ba998594a1
new file mode 100644 (file)
index 0000000..3de2c87
Binary files /dev/null and b/fuzzers/corpora/commit_graph/125a228afb923970e0a6d4412f7257ba998594a1 differ
diff --git a/fuzzers/corpora/commit_graph/130d96c16fba06dcbe7e2a661ab959a3274a4bd9 b/fuzzers/corpora/commit_graph/130d96c16fba06dcbe7e2a661ab959a3274a4bd9
new file mode 100644 (file)
index 0000000..66a4097
Binary files /dev/null and b/fuzzers/corpora/commit_graph/130d96c16fba06dcbe7e2a661ab959a3274a4bd9 differ
diff --git a/fuzzers/corpora/commit_graph/131c5a2fec55cb0d63f7dc055d6fad5f3dc3c974 b/fuzzers/corpora/commit_graph/131c5a2fec55cb0d63f7dc055d6fad5f3dc3c974
new file mode 100644 (file)
index 0000000..b54bfad
Binary files /dev/null and b/fuzzers/corpora/commit_graph/131c5a2fec55cb0d63f7dc055d6fad5f3dc3c974 differ
diff --git a/fuzzers/corpora/commit_graph/13e562d61acb3aa36260a819a00b07ff16450335 b/fuzzers/corpora/commit_graph/13e562d61acb3aa36260a819a00b07ff16450335
new file mode 100644 (file)
index 0000000..6682c84
Binary files /dev/null and b/fuzzers/corpora/commit_graph/13e562d61acb3aa36260a819a00b07ff16450335 differ
diff --git a/fuzzers/corpora/commit_graph/1414e6e8ab6bad1b5c51fed807c514a9d6575e66 b/fuzzers/corpora/commit_graph/1414e6e8ab6bad1b5c51fed807c514a9d6575e66
new file mode 100644 (file)
index 0000000..c7f2386
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1414e6e8ab6bad1b5c51fed807c514a9d6575e66 differ
diff --git a/fuzzers/corpora/commit_graph/1432d191846ae2d0e381813efcfacff2f1dba0e4 b/fuzzers/corpora/commit_graph/1432d191846ae2d0e381813efcfacff2f1dba0e4
new file mode 100644 (file)
index 0000000..cf5b990
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1432d191846ae2d0e381813efcfacff2f1dba0e4 differ
diff --git a/fuzzers/corpora/commit_graph/14a84cdc6f8d432be4cd3d3eafce92ae385e472f b/fuzzers/corpora/commit_graph/14a84cdc6f8d432be4cd3d3eafce92ae385e472f
new file mode 100644 (file)
index 0000000..8f86651
Binary files /dev/null and b/fuzzers/corpora/commit_graph/14a84cdc6f8d432be4cd3d3eafce92ae385e472f differ
diff --git a/fuzzers/corpora/commit_graph/14e3e735dba88791f2cadd6e0dc5d662a104a6d7 b/fuzzers/corpora/commit_graph/14e3e735dba88791f2cadd6e0dc5d662a104a6d7
new file mode 100644 (file)
index 0000000..32fb993
Binary files /dev/null and b/fuzzers/corpora/commit_graph/14e3e735dba88791f2cadd6e0dc5d662a104a6d7 differ
diff --git a/fuzzers/corpora/commit_graph/1574abb020203103ea629d677edd21c967fc0f4c b/fuzzers/corpora/commit_graph/1574abb020203103ea629d677edd21c967fc0f4c
new file mode 100644 (file)
index 0000000..b3da74c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1574abb020203103ea629d677edd21c967fc0f4c differ
diff --git a/fuzzers/corpora/commit_graph/169cc492ba94948a6206765436881a1a0c601780 b/fuzzers/corpora/commit_graph/169cc492ba94948a6206765436881a1a0c601780
new file mode 100644 (file)
index 0000000..2ce25f6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/169cc492ba94948a6206765436881a1a0c601780 differ
diff --git a/fuzzers/corpora/commit_graph/16a2130c1d75129f3bae3bf8f2c2de41fb3533c0 b/fuzzers/corpora/commit_graph/16a2130c1d75129f3bae3bf8f2c2de41fb3533c0
new file mode 100644 (file)
index 0000000..0b66385
Binary files /dev/null and b/fuzzers/corpora/commit_graph/16a2130c1d75129f3bae3bf8f2c2de41fb3533c0 differ
diff --git a/fuzzers/corpora/commit_graph/16ba602eadfc9a3f74c0845394eda0de42b61571 b/fuzzers/corpora/commit_graph/16ba602eadfc9a3f74c0845394eda0de42b61571
new file mode 100644 (file)
index 0000000..c44bd06
Binary files /dev/null and b/fuzzers/corpora/commit_graph/16ba602eadfc9a3f74c0845394eda0de42b61571 differ
diff --git a/fuzzers/corpora/commit_graph/17555fb2dfc444d171ba686667d72e388bd6c041 b/fuzzers/corpora/commit_graph/17555fb2dfc444d171ba686667d72e388bd6c041
new file mode 100644 (file)
index 0000000..3d00026
Binary files /dev/null and b/fuzzers/corpora/commit_graph/17555fb2dfc444d171ba686667d72e388bd6c041 differ
diff --git a/fuzzers/corpora/commit_graph/1a10450d99c1e53d9b7f97b8014cb7fc01906ef2 b/fuzzers/corpora/commit_graph/1a10450d99c1e53d9b7f97b8014cb7fc01906ef2
new file mode 100644 (file)
index 0000000..f1fec60
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1a10450d99c1e53d9b7f97b8014cb7fc01906ef2 differ
diff --git a/fuzzers/corpora/commit_graph/1af670b5515231fc04b2be9038ee30a7e066b09b b/fuzzers/corpora/commit_graph/1af670b5515231fc04b2be9038ee30a7e066b09b
new file mode 100644 (file)
index 0000000..3bf7345
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1af670b5515231fc04b2be9038ee30a7e066b09b differ
diff --git a/fuzzers/corpora/commit_graph/1b72cfa68259e3f3b3802906902a0a29368f86b5 b/fuzzers/corpora/commit_graph/1b72cfa68259e3f3b3802906902a0a29368f86b5
new file mode 100644 (file)
index 0000000..e6509d1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1b72cfa68259e3f3b3802906902a0a29368f86b5 differ
diff --git a/fuzzers/corpora/commit_graph/1c62ac5d632aa9e449a4335b675941107d8825ae b/fuzzers/corpora/commit_graph/1c62ac5d632aa9e449a4335b675941107d8825ae
new file mode 100644 (file)
index 0000000..10c9e74
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1c62ac5d632aa9e449a4335b675941107d8825ae differ
diff --git a/fuzzers/corpora/commit_graph/1d95b5db2f802011b33d10212a66fbe40827dfd4 b/fuzzers/corpora/commit_graph/1d95b5db2f802011b33d10212a66fbe40827dfd4
new file mode 100644 (file)
index 0000000..2353450
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1d95b5db2f802011b33d10212a66fbe40827dfd4 differ
diff --git a/fuzzers/corpora/commit_graph/1e068537ce1211a325aab42ae1263a109131c9f9 b/fuzzers/corpora/commit_graph/1e068537ce1211a325aab42ae1263a109131c9f9
new file mode 100644 (file)
index 0000000..0351738
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1e068537ce1211a325aab42ae1263a109131c9f9 differ
diff --git a/fuzzers/corpora/commit_graph/1e9c882c9d33304a5791ef6c98eee65e142bd7fd b/fuzzers/corpora/commit_graph/1e9c882c9d33304a5791ef6c98eee65e142bd7fd
new file mode 100644 (file)
index 0000000..d5b9da4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1e9c882c9d33304a5791ef6c98eee65e142bd7fd differ
diff --git a/fuzzers/corpora/commit_graph/1f54935df929403a29e77591c97f767d94871aea b/fuzzers/corpora/commit_graph/1f54935df929403a29e77591c97f767d94871aea
new file mode 100644 (file)
index 0000000..6f9b0a0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/1f54935df929403a29e77591c97f767d94871aea differ
diff --git a/fuzzers/corpora/commit_graph/206015659641771bb0d668728c2fdc4209e65dda b/fuzzers/corpora/commit_graph/206015659641771bb0d668728c2fdc4209e65dda
new file mode 100644 (file)
index 0000000..086ab64
Binary files /dev/null and b/fuzzers/corpora/commit_graph/206015659641771bb0d668728c2fdc4209e65dda differ
diff --git a/fuzzers/corpora/commit_graph/2096493a2bcc2d15b7ae5bf3112fe49c39976ad8 b/fuzzers/corpora/commit_graph/2096493a2bcc2d15b7ae5bf3112fe49c39976ad8
new file mode 100644 (file)
index 0000000..7b33d38
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2096493a2bcc2d15b7ae5bf3112fe49c39976ad8 differ
diff --git a/fuzzers/corpora/commit_graph/209b74e08abe8c787b7c5ba81e51cb69c57ecded b/fuzzers/corpora/commit_graph/209b74e08abe8c787b7c5ba81e51cb69c57ecded
new file mode 100644 (file)
index 0000000..55dca76
Binary files /dev/null and b/fuzzers/corpora/commit_graph/209b74e08abe8c787b7c5ba81e51cb69c57ecded differ
diff --git a/fuzzers/corpora/commit_graph/21137876575fbca357fc0c96db1de73c6737e1ae b/fuzzers/corpora/commit_graph/21137876575fbca357fc0c96db1de73c6737e1ae
new file mode 100644 (file)
index 0000000..fea1ac1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/21137876575fbca357fc0c96db1de73c6737e1ae differ
diff --git a/fuzzers/corpora/commit_graph/2143d9db9802f076c72a71184cd9d0cb4581e9e7 b/fuzzers/corpora/commit_graph/2143d9db9802f076c72a71184cd9d0cb4581e9e7
new file mode 100644 (file)
index 0000000..bacbe88
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2143d9db9802f076c72a71184cd9d0cb4581e9e7 differ
diff --git a/fuzzers/corpora/commit_graph/21a52a5282145407d951ac73c2ff27876783899d b/fuzzers/corpora/commit_graph/21a52a5282145407d951ac73c2ff27876783899d
new file mode 100644 (file)
index 0000000..1b5d2f0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/21a52a5282145407d951ac73c2ff27876783899d differ
diff --git a/fuzzers/corpora/commit_graph/21d5c8c8ac3a09bcba5388c472df32795986a5cb b/fuzzers/corpora/commit_graph/21d5c8c8ac3a09bcba5388c472df32795986a5cb
new file mode 100644 (file)
index 0000000..b148c6f
--- /dev/null
@@ -0,0 +1 @@
+ÿúÿ¦
\ No newline at end of file
diff --git a/fuzzers/corpora/commit_graph/22170d1110a1c18009b7feb21a470681f55e85fb b/fuzzers/corpora/commit_graph/22170d1110a1c18009b7feb21a470681f55e85fb
new file mode 100644 (file)
index 0000000..6c16354
Binary files /dev/null and b/fuzzers/corpora/commit_graph/22170d1110a1c18009b7feb21a470681f55e85fb differ
diff --git a/fuzzers/corpora/commit_graph/22f55dff94785f24252d7a070f713840f59b0870 b/fuzzers/corpora/commit_graph/22f55dff94785f24252d7a070f713840f59b0870
new file mode 100644 (file)
index 0000000..b45c99a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/22f55dff94785f24252d7a070f713840f59b0870 differ
diff --git a/fuzzers/corpora/commit_graph/23d10ee9694e1c66bedc7060990f19a2ac3eaee3 b/fuzzers/corpora/commit_graph/23d10ee9694e1c66bedc7060990f19a2ac3eaee3
new file mode 100644 (file)
index 0000000..8790bfd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/23d10ee9694e1c66bedc7060990f19a2ac3eaee3 differ
diff --git a/fuzzers/corpora/commit_graph/2435430ca19502c3b0ec4987508d4a8fbdbc898c b/fuzzers/corpora/commit_graph/2435430ca19502c3b0ec4987508d4a8fbdbc898c
new file mode 100644 (file)
index 0000000..e1d58bd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2435430ca19502c3b0ec4987508d4a8fbdbc898c differ
diff --git a/fuzzers/corpora/commit_graph/244d2ea0c5c3117000b599cfab37680ba8f04513 b/fuzzers/corpora/commit_graph/244d2ea0c5c3117000b599cfab37680ba8f04513
new file mode 100644 (file)
index 0000000..5eedc85
Binary files /dev/null and b/fuzzers/corpora/commit_graph/244d2ea0c5c3117000b599cfab37680ba8f04513 differ
diff --git a/fuzzers/corpora/commit_graph/248bf94143d150da2459cfdca099c30c6daff00a b/fuzzers/corpora/commit_graph/248bf94143d150da2459cfdca099c30c6daff00a
new file mode 100644 (file)
index 0000000..8b5f81b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/248bf94143d150da2459cfdca099c30c6daff00a differ
diff --git a/fuzzers/corpora/commit_graph/25bc53498129bb3717671f00c355d2637a91c86a b/fuzzers/corpora/commit_graph/25bc53498129bb3717671f00c355d2637a91c86a
new file mode 100644 (file)
index 0000000..d86bb32
Binary files /dev/null and b/fuzzers/corpora/commit_graph/25bc53498129bb3717671f00c355d2637a91c86a differ
diff --git a/fuzzers/corpora/commit_graph/2614f60da2d7e291501397238366d27513bff773 b/fuzzers/corpora/commit_graph/2614f60da2d7e291501397238366d27513bff773
new file mode 100644 (file)
index 0000000..57cd70a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2614f60da2d7e291501397238366d27513bff773 differ
diff --git a/fuzzers/corpora/commit_graph/2651b3d5a8b4616b1faa81dabe27ab2712a27561 b/fuzzers/corpora/commit_graph/2651b3d5a8b4616b1faa81dabe27ab2712a27561
new file mode 100644 (file)
index 0000000..5f838de
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2651b3d5a8b4616b1faa81dabe27ab2712a27561 differ
diff --git a/fuzzers/corpora/commit_graph/270257a2872b33dd13c4fd466cbc1ae67d613f9b b/fuzzers/corpora/commit_graph/270257a2872b33dd13c4fd466cbc1ae67d613f9b
new file mode 100644 (file)
index 0000000..3090496
Binary files /dev/null and b/fuzzers/corpora/commit_graph/270257a2872b33dd13c4fd466cbc1ae67d613f9b differ
diff --git a/fuzzers/corpora/commit_graph/2830c6244c74656f6c5649c8226953905a582a38 b/fuzzers/corpora/commit_graph/2830c6244c74656f6c5649c8226953905a582a38
new file mode 100644 (file)
index 0000000..895a8ef
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2830c6244c74656f6c5649c8226953905a582a38 differ
diff --git a/fuzzers/corpora/commit_graph/2889a85c07c20551ff0b97fc640e3c91b33aa4a1 b/fuzzers/corpora/commit_graph/2889a85c07c20551ff0b97fc640e3c91b33aa4a1
new file mode 100644 (file)
index 0000000..349ff15
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2889a85c07c20551ff0b97fc640e3c91b33aa4a1 differ
diff --git a/fuzzers/corpora/commit_graph/295ce43fdd56def8948d1ba2bfa7fdf0c47b5318 b/fuzzers/corpora/commit_graph/295ce43fdd56def8948d1ba2bfa7fdf0c47b5318
new file mode 100644 (file)
index 0000000..4a3ce80
Binary files /dev/null and b/fuzzers/corpora/commit_graph/295ce43fdd56def8948d1ba2bfa7fdf0c47b5318 differ
diff --git a/fuzzers/corpora/commit_graph/296cbb94c4e68ab86972a174405308ee34d0c40f b/fuzzers/corpora/commit_graph/296cbb94c4e68ab86972a174405308ee34d0c40f
new file mode 100644 (file)
index 0000000..45c218e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/296cbb94c4e68ab86972a174405308ee34d0c40f differ
diff --git a/fuzzers/corpora/commit_graph/2975adf222cad108ec90d8225fd655e30e3bf253 b/fuzzers/corpora/commit_graph/2975adf222cad108ec90d8225fd655e30e3bf253
new file mode 100644 (file)
index 0000000..6a16429
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2975adf222cad108ec90d8225fd655e30e3bf253 differ
diff --git a/fuzzers/corpora/commit_graph/29f5d27760c9254ab4db661a6cd0323dd11c34ca b/fuzzers/corpora/commit_graph/29f5d27760c9254ab4db661a6cd0323dd11c34ca
new file mode 100644 (file)
index 0000000..a9d81e1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/29f5d27760c9254ab4db661a6cd0323dd11c34ca differ
diff --git a/fuzzers/corpora/commit_graph/2a359fb09eaad968e57d353453908027645873d1 b/fuzzers/corpora/commit_graph/2a359fb09eaad968e57d353453908027645873d1
new file mode 100644 (file)
index 0000000..a17910b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2a359fb09eaad968e57d353453908027645873d1 differ
diff --git a/fuzzers/corpora/commit_graph/2a6b65a8d6c28febaa081d220a4433f8366d02bc b/fuzzers/corpora/commit_graph/2a6b65a8d6c28febaa081d220a4433f8366d02bc
new file mode 100644 (file)
index 0000000..597f363
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2a6b65a8d6c28febaa081d220a4433f8366d02bc differ
diff --git a/fuzzers/corpora/commit_graph/2b14dcade4d0919b0a17830fe353738015f492a6 b/fuzzers/corpora/commit_graph/2b14dcade4d0919b0a17830fe353738015f492a6
new file mode 100644 (file)
index 0000000..33f4e6e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2b14dcade4d0919b0a17830fe353738015f492a6 differ
diff --git a/fuzzers/corpora/commit_graph/2b298a13abbd9829e965424a1486baa13d4166c4 b/fuzzers/corpora/commit_graph/2b298a13abbd9829e965424a1486baa13d4166c4
new file mode 100644 (file)
index 0000000..837e45f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2b298a13abbd9829e965424a1486baa13d4166c4 differ
diff --git a/fuzzers/corpora/commit_graph/2b44d8cd8e70e25172b4c740ebe38ef411c965b3 b/fuzzers/corpora/commit_graph/2b44d8cd8e70e25172b4c740ebe38ef411c965b3
new file mode 100644 (file)
index 0000000..8059ce4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2b44d8cd8e70e25172b4c740ebe38ef411c965b3 differ
diff --git a/fuzzers/corpora/commit_graph/2b590c4e61fdfcf21c017b29440747a1894b1534 b/fuzzers/corpora/commit_graph/2b590c4e61fdfcf21c017b29440747a1894b1534
new file mode 100644 (file)
index 0000000..c3ea729
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2b590c4e61fdfcf21c017b29440747a1894b1534 differ
diff --git a/fuzzers/corpora/commit_graph/2becb18a971ae30e1a8f6680982fd7305708caa0 b/fuzzers/corpora/commit_graph/2becb18a971ae30e1a8f6680982fd7305708caa0
new file mode 100644 (file)
index 0000000..4b133a7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2becb18a971ae30e1a8f6680982fd7305708caa0 differ
diff --git a/fuzzers/corpora/commit_graph/2bf78b02099a1fe4ce50d065254e843ca55e280f b/fuzzers/corpora/commit_graph/2bf78b02099a1fe4ce50d065254e843ca55e280f
new file mode 100644 (file)
index 0000000..9b459e2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2bf78b02099a1fe4ce50d065254e843ca55e280f differ
diff --git a/fuzzers/corpora/commit_graph/2c1541ecd01aa7b9e99bccfe9804198b3e79f118 b/fuzzers/corpora/commit_graph/2c1541ecd01aa7b9e99bccfe9804198b3e79f118
new file mode 100644 (file)
index 0000000..92daa0a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2c1541ecd01aa7b9e99bccfe9804198b3e79f118 differ
diff --git a/fuzzers/corpora/commit_graph/2c6798057af5894c27631ff63e845fe1e4bdc9ee b/fuzzers/corpora/commit_graph/2c6798057af5894c27631ff63e845fe1e4bdc9ee
new file mode 100644 (file)
index 0000000..06a7d31
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2c6798057af5894c27631ff63e845fe1e4bdc9ee differ
diff --git a/fuzzers/corpora/commit_graph/2cf7eb7fe489e5acd64df755e820c871784c2ba1 b/fuzzers/corpora/commit_graph/2cf7eb7fe489e5acd64df755e820c871784c2ba1
new file mode 100644 (file)
index 0000000..5614c74
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2cf7eb7fe489e5acd64df755e820c871784c2ba1 differ
diff --git a/fuzzers/corpora/commit_graph/2d49ba35ca404baa0d593925f36a81ce53943c8d b/fuzzers/corpora/commit_graph/2d49ba35ca404baa0d593925f36a81ce53943c8d
new file mode 100644 (file)
index 0000000..36d6b85
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2d49ba35ca404baa0d593925f36a81ce53943c8d differ
diff --git a/fuzzers/corpora/commit_graph/2d507d42ca43ffc2f3c8892826e1db74144ec096 b/fuzzers/corpora/commit_graph/2d507d42ca43ffc2f3c8892826e1db74144ec096
new file mode 100644 (file)
index 0000000..35c28f4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2d507d42ca43ffc2f3c8892826e1db74144ec096 differ
diff --git a/fuzzers/corpora/commit_graph/2e4da693e3e336d2b1a40311a7ccf94def035b6b b/fuzzers/corpora/commit_graph/2e4da693e3e336d2b1a40311a7ccf94def035b6b
new file mode 100644 (file)
index 0000000..42727e9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2e4da693e3e336d2b1a40311a7ccf94def035b6b differ
diff --git a/fuzzers/corpora/commit_graph/2e71ff86128b5618f0f067c407a76ff645ae2019 b/fuzzers/corpora/commit_graph/2e71ff86128b5618f0f067c407a76ff645ae2019
new file mode 100644 (file)
index 0000000..32f02fc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2e71ff86128b5618f0f067c407a76ff645ae2019 differ
diff --git a/fuzzers/corpora/commit_graph/2eb777c6d7e6ee9bd7a44e37372595043aad596b b/fuzzers/corpora/commit_graph/2eb777c6d7e6ee9bd7a44e37372595043aad596b
new file mode 100644 (file)
index 0000000..7203c91
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2eb777c6d7e6ee9bd7a44e37372595043aad596b differ
diff --git a/fuzzers/corpora/commit_graph/2ec3ebffba165b9dd49e755a9e77e23aed796628 b/fuzzers/corpora/commit_graph/2ec3ebffba165b9dd49e755a9e77e23aed796628
new file mode 100644 (file)
index 0000000..d4018de
Binary files /dev/null and b/fuzzers/corpora/commit_graph/2ec3ebffba165b9dd49e755a9e77e23aed796628 differ
diff --git a/fuzzers/corpora/commit_graph/302703e3b0d74219868aca39ee7593944c0b2400 b/fuzzers/corpora/commit_graph/302703e3b0d74219868aca39ee7593944c0b2400
new file mode 100644 (file)
index 0000000..6b692e1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/302703e3b0d74219868aca39ee7593944c0b2400 differ
diff --git a/fuzzers/corpora/commit_graph/3048c6908dc3176707fa8bcb0196824e3358357a b/fuzzers/corpora/commit_graph/3048c6908dc3176707fa8bcb0196824e3358357a
new file mode 100644 (file)
index 0000000..c58805f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3048c6908dc3176707fa8bcb0196824e3358357a differ
diff --git a/fuzzers/corpora/commit_graph/30616cb39d3ad6060324fada03709d611ad28d5c b/fuzzers/corpora/commit_graph/30616cb39d3ad6060324fada03709d611ad28d5c
new file mode 100644 (file)
index 0000000..1fd655e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/30616cb39d3ad6060324fada03709d611ad28d5c differ
diff --git a/fuzzers/corpora/commit_graph/306beadd9b3135a00037323760eb5377c88a403e b/fuzzers/corpora/commit_graph/306beadd9b3135a00037323760eb5377c88a403e
new file mode 100644 (file)
index 0000000..86c8672
Binary files /dev/null and b/fuzzers/corpora/commit_graph/306beadd9b3135a00037323760eb5377c88a403e differ
diff --git a/fuzzers/corpora/commit_graph/31464a6fbad023923a7e4700fc11564e811bcbd2 b/fuzzers/corpora/commit_graph/31464a6fbad023923a7e4700fc11564e811bcbd2
new file mode 100644 (file)
index 0000000..102de5c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/31464a6fbad023923a7e4700fc11564e811bcbd2 differ
diff --git a/fuzzers/corpora/commit_graph/317f4bcfecf066961ef1982d551cd14e63c9f008 b/fuzzers/corpora/commit_graph/317f4bcfecf066961ef1982d551cd14e63c9f008
new file mode 100644 (file)
index 0000000..5c2a5d7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/317f4bcfecf066961ef1982d551cd14e63c9f008 differ
diff --git a/fuzzers/corpora/commit_graph/31b2248faaabbec69a06098c8cb0f69c5d0aa208 b/fuzzers/corpora/commit_graph/31b2248faaabbec69a06098c8cb0f69c5d0aa208
new file mode 100644 (file)
index 0000000..555c7b1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/31b2248faaabbec69a06098c8cb0f69c5d0aa208 differ
diff --git a/fuzzers/corpora/commit_graph/31d1c3d1147385d58dbe6f82898a5523320fbcac b/fuzzers/corpora/commit_graph/31d1c3d1147385d58dbe6f82898a5523320fbcac
new file mode 100644 (file)
index 0000000..1c5ef07
Binary files /dev/null and b/fuzzers/corpora/commit_graph/31d1c3d1147385d58dbe6f82898a5523320fbcac differ
diff --git a/fuzzers/corpora/commit_graph/32c9bc1616a78a230a3724abc02150db1cc40aa0 b/fuzzers/corpora/commit_graph/32c9bc1616a78a230a3724abc02150db1cc40aa0
new file mode 100644 (file)
index 0000000..cfc45a1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/32c9bc1616a78a230a3724abc02150db1cc40aa0 differ
diff --git a/fuzzers/corpora/commit_graph/331e2866416b091252f0299e98d32cfb29237029 b/fuzzers/corpora/commit_graph/331e2866416b091252f0299e98d32cfb29237029
new file mode 100644 (file)
index 0000000..241e719
Binary files /dev/null and b/fuzzers/corpora/commit_graph/331e2866416b091252f0299e98d32cfb29237029 differ
diff --git a/fuzzers/corpora/commit_graph/331eb3876dd2f3f0bd51f380ac431d86d6e3bb5e b/fuzzers/corpora/commit_graph/331eb3876dd2f3f0bd51f380ac431d86d6e3bb5e
new file mode 100644 (file)
index 0000000..a52780f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/331eb3876dd2f3f0bd51f380ac431d86d6e3bb5e differ
diff --git a/fuzzers/corpora/commit_graph/346bd6eaeadeafcb840ff9441614b309330db63e b/fuzzers/corpora/commit_graph/346bd6eaeadeafcb840ff9441614b309330db63e
new file mode 100644 (file)
index 0000000..50b7f93
Binary files /dev/null and b/fuzzers/corpora/commit_graph/346bd6eaeadeafcb840ff9441614b309330db63e differ
diff --git a/fuzzers/corpora/commit_graph/349931f447981f21476481448576e805c093a25b b/fuzzers/corpora/commit_graph/349931f447981f21476481448576e805c093a25b
new file mode 100644 (file)
index 0000000..ae5b758
Binary files /dev/null and b/fuzzers/corpora/commit_graph/349931f447981f21476481448576e805c093a25b differ
diff --git a/fuzzers/corpora/commit_graph/34a2da1e9adaac1b4be1d40b1ece81fe00643d49 b/fuzzers/corpora/commit_graph/34a2da1e9adaac1b4be1d40b1ece81fe00643d49
new file mode 100644 (file)
index 0000000..f5d660f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/34a2da1e9adaac1b4be1d40b1ece81fe00643d49 differ
diff --git a/fuzzers/corpora/commit_graph/34bb8f475e7384a8a39618fd15fdc5fb1b12c1a1 b/fuzzers/corpora/commit_graph/34bb8f475e7384a8a39618fd15fdc5fb1b12c1a1
new file mode 100644 (file)
index 0000000..f940f66
Binary files /dev/null and b/fuzzers/corpora/commit_graph/34bb8f475e7384a8a39618fd15fdc5fb1b12c1a1 differ
diff --git a/fuzzers/corpora/commit_graph/351a036c6eb95db9364706b861f7e75ad26194e8 b/fuzzers/corpora/commit_graph/351a036c6eb95db9364706b861f7e75ad26194e8
new file mode 100644 (file)
index 0000000..197bee1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/351a036c6eb95db9364706b861f7e75ad26194e8 differ
diff --git a/fuzzers/corpora/commit_graph/355452c1da8e7689d816d67cdde040b5df7eabd7 b/fuzzers/corpora/commit_graph/355452c1da8e7689d816d67cdde040b5df7eabd7
new file mode 100644 (file)
index 0000000..f135872
Binary files /dev/null and b/fuzzers/corpora/commit_graph/355452c1da8e7689d816d67cdde040b5df7eabd7 differ
diff --git a/fuzzers/corpora/commit_graph/35c157ad2b100b4f334cddcf3dea6ef2d85462be b/fuzzers/corpora/commit_graph/35c157ad2b100b4f334cddcf3dea6ef2d85462be
new file mode 100644 (file)
index 0000000..7d73ba7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/35c157ad2b100b4f334cddcf3dea6ef2d85462be differ
diff --git a/fuzzers/corpora/commit_graph/36a81a45eabfcf53e1ae0361aa234791e2fdb750 b/fuzzers/corpora/commit_graph/36a81a45eabfcf53e1ae0361aa234791e2fdb750
new file mode 100644 (file)
index 0000000..fc1b8dd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/36a81a45eabfcf53e1ae0361aa234791e2fdb750 differ
diff --git a/fuzzers/corpora/commit_graph/36ee20f6dbeb3a34e91eafbbe2e379f9ac6cfa43 b/fuzzers/corpora/commit_graph/36ee20f6dbeb3a34e91eafbbe2e379f9ac6cfa43
new file mode 100644 (file)
index 0000000..769017a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/36ee20f6dbeb3a34e91eafbbe2e379f9ac6cfa43 differ
diff --git a/fuzzers/corpora/commit_graph/377627c19bcac6adc880202048a9eac07b5417d4 b/fuzzers/corpora/commit_graph/377627c19bcac6adc880202048a9eac07b5417d4
new file mode 100644 (file)
index 0000000..d4ef66b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/377627c19bcac6adc880202048a9eac07b5417d4 differ
diff --git a/fuzzers/corpora/commit_graph/38747e7c8bec2f9c923739d50ba54ff88ba6503f b/fuzzers/corpora/commit_graph/38747e7c8bec2f9c923739d50ba54ff88ba6503f
new file mode 100644 (file)
index 0000000..6d94b57
Binary files /dev/null and b/fuzzers/corpora/commit_graph/38747e7c8bec2f9c923739d50ba54ff88ba6503f differ
diff --git a/fuzzers/corpora/commit_graph/3945843a6fab2ec71030f09b237c125b97cd3ea5 b/fuzzers/corpora/commit_graph/3945843a6fab2ec71030f09b237c125b97cd3ea5
new file mode 100644 (file)
index 0000000..76191ca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3945843a6fab2ec71030f09b237c125b97cd3ea5 differ
diff --git a/fuzzers/corpora/commit_graph/396321d39b82ffaccbc64115117df7e822b0f515 b/fuzzers/corpora/commit_graph/396321d39b82ffaccbc64115117df7e822b0f515
new file mode 100644 (file)
index 0000000..74715a9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/396321d39b82ffaccbc64115117df7e822b0f515 differ
diff --git a/fuzzers/corpora/commit_graph/396e78eb9b54e2cefb52cd76a22137c8abd6cbcf b/fuzzers/corpora/commit_graph/396e78eb9b54e2cefb52cd76a22137c8abd6cbcf
new file mode 100644 (file)
index 0000000..b5648c4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/396e78eb9b54e2cefb52cd76a22137c8abd6cbcf differ
diff --git a/fuzzers/corpora/commit_graph/39c1ab66035adc104cd06a6d98b77668172d21af b/fuzzers/corpora/commit_graph/39c1ab66035adc104cd06a6d98b77668172d21af
new file mode 100644 (file)
index 0000000..f9649f7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/39c1ab66035adc104cd06a6d98b77668172d21af differ
diff --git a/fuzzers/corpora/commit_graph/3a1078c35f5401ce09b5ba921fc348dde37530bb b/fuzzers/corpora/commit_graph/3a1078c35f5401ce09b5ba921fc348dde37530bb
new file mode 100644 (file)
index 0000000..7e519f8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3a1078c35f5401ce09b5ba921fc348dde37530bb differ
diff --git a/fuzzers/corpora/commit_graph/3aa3d8f40392d1c863d23799b8ec0aedc7191302 b/fuzzers/corpora/commit_graph/3aa3d8f40392d1c863d23799b8ec0aedc7191302
new file mode 100644 (file)
index 0000000..3cbeaaf
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3aa3d8f40392d1c863d23799b8ec0aedc7191302 differ
diff --git a/fuzzers/corpora/commit_graph/3b08c505601271cb92345ec7f0ff0b28daf90a9c b/fuzzers/corpora/commit_graph/3b08c505601271cb92345ec7f0ff0b28daf90a9c
new file mode 100644 (file)
index 0000000..69b9bab
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3b08c505601271cb92345ec7f0ff0b28daf90a9c differ
diff --git a/fuzzers/corpora/commit_graph/3b41702587be45f678b36823ad2f7e5002337dc4 b/fuzzers/corpora/commit_graph/3b41702587be45f678b36823ad2f7e5002337dc4
new file mode 100644 (file)
index 0000000..29069ab
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3b41702587be45f678b36823ad2f7e5002337dc4 differ
diff --git a/fuzzers/corpora/commit_graph/3b69108cc919aba0248f9b864d4e71c5f6d1931e b/fuzzers/corpora/commit_graph/3b69108cc919aba0248f9b864d4e71c5f6d1931e
new file mode 100644 (file)
index 0000000..207df24
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3b69108cc919aba0248f9b864d4e71c5f6d1931e differ
diff --git a/fuzzers/corpora/commit_graph/3b90507501bb3bcfe0094f9c92cc2869f1a7dda5 b/fuzzers/corpora/commit_graph/3b90507501bb3bcfe0094f9c92cc2869f1a7dda5
new file mode 100644 (file)
index 0000000..5727232
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3b90507501bb3bcfe0094f9c92cc2869f1a7dda5 differ
diff --git a/fuzzers/corpora/commit_graph/3bc7fe44c3a1464dd35a4d22b482f46cdeda0405 b/fuzzers/corpora/commit_graph/3bc7fe44c3a1464dd35a4d22b482f46cdeda0405
new file mode 100644 (file)
index 0000000..e1a8bd3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3bc7fe44c3a1464dd35a4d22b482f46cdeda0405 differ
diff --git a/fuzzers/corpora/commit_graph/3ce99994986efb6df3f3568423e0077b53c7ef78 b/fuzzers/corpora/commit_graph/3ce99994986efb6df3f3568423e0077b53c7ef78
new file mode 100644 (file)
index 0000000..21f9ab8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3ce99994986efb6df3f3568423e0077b53c7ef78 differ
diff --git a/fuzzers/corpora/commit_graph/3d6cb3ba21181c9f0ab08b2608eab773f36773f2 b/fuzzers/corpora/commit_graph/3d6cb3ba21181c9f0ab08b2608eab773f36773f2
new file mode 100644 (file)
index 0000000..548a129
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3d6cb3ba21181c9f0ab08b2608eab773f36773f2 differ
diff --git a/fuzzers/corpora/commit_graph/3d8ec41450b943d5dea73fb1e393960b03d7c3b9 b/fuzzers/corpora/commit_graph/3d8ec41450b943d5dea73fb1e393960b03d7c3b9
new file mode 100644 (file)
index 0000000..150ed2c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3d8ec41450b943d5dea73fb1e393960b03d7c3b9 differ
diff --git a/fuzzers/corpora/commit_graph/3e29e8baaac0f6c7e4cf3d5adca2ab3a2c491ac7 b/fuzzers/corpora/commit_graph/3e29e8baaac0f6c7e4cf3d5adca2ab3a2c491ac7
new file mode 100644 (file)
index 0000000..bc9597d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3e29e8baaac0f6c7e4cf3d5adca2ab3a2c491ac7 differ
diff --git a/fuzzers/corpora/commit_graph/3e9469b3c68ba334671aacda7a7669b0e97b74d6 b/fuzzers/corpora/commit_graph/3e9469b3c68ba334671aacda7a7669b0e97b74d6
new file mode 100644 (file)
index 0000000..cb20df0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3e9469b3c68ba334671aacda7a7669b0e97b74d6 differ
diff --git a/fuzzers/corpora/commit_graph/3eeda3bfa7abef69911c94520c009a08c49b9942 b/fuzzers/corpora/commit_graph/3eeda3bfa7abef69911c94520c009a08c49b9942
new file mode 100644 (file)
index 0000000..dbf559f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3eeda3bfa7abef69911c94520c009a08c49b9942 differ
diff --git a/fuzzers/corpora/commit_graph/3f0f5021016451b57f673d0603cd9e4830c2198d b/fuzzers/corpora/commit_graph/3f0f5021016451b57f673d0603cd9e4830c2198d
new file mode 100644 (file)
index 0000000..2f4c523
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3f0f5021016451b57f673d0603cd9e4830c2198d differ
diff --git a/fuzzers/corpora/commit_graph/3f46540fbd94bf0337c1d0d7437ec992a3568f09 b/fuzzers/corpora/commit_graph/3f46540fbd94bf0337c1d0d7437ec992a3568f09
new file mode 100644 (file)
index 0000000..7fbf350
Binary files /dev/null and b/fuzzers/corpora/commit_graph/3f46540fbd94bf0337c1d0d7437ec992a3568f09 differ
diff --git a/fuzzers/corpora/commit_graph/402d9c25d5833d42630882ab5c57833266bef785 b/fuzzers/corpora/commit_graph/402d9c25d5833d42630882ab5c57833266bef785
new file mode 100644 (file)
index 0000000..6600281
Binary files /dev/null and b/fuzzers/corpora/commit_graph/402d9c25d5833d42630882ab5c57833266bef785 differ
diff --git a/fuzzers/corpora/commit_graph/4048bb3c26d67c345630ff9e86db551a3add6549 b/fuzzers/corpora/commit_graph/4048bb3c26d67c345630ff9e86db551a3add6549
new file mode 100644 (file)
index 0000000..a07e195
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4048bb3c26d67c345630ff9e86db551a3add6549 differ
diff --git a/fuzzers/corpora/commit_graph/40792f23c1281842dab671e8b213fc408d1ec39f b/fuzzers/corpora/commit_graph/40792f23c1281842dab671e8b213fc408d1ec39f
new file mode 100644 (file)
index 0000000..9a0f9c2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/40792f23c1281842dab671e8b213fc408d1ec39f differ
diff --git a/fuzzers/corpora/commit_graph/41cd0b5d9a9540947b7b1841a55e4c11bd4346a2 b/fuzzers/corpora/commit_graph/41cd0b5d9a9540947b7b1841a55e4c11bd4346a2
new file mode 100644 (file)
index 0000000..a1b3a07
Binary files /dev/null and b/fuzzers/corpora/commit_graph/41cd0b5d9a9540947b7b1841a55e4c11bd4346a2 differ
diff --git a/fuzzers/corpora/commit_graph/41d86e5ea3df4a0de60d42aeb16e2a5599aedeae b/fuzzers/corpora/commit_graph/41d86e5ea3df4a0de60d42aeb16e2a5599aedeae
new file mode 100644 (file)
index 0000000..d749cf6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/41d86e5ea3df4a0de60d42aeb16e2a5599aedeae differ
diff --git a/fuzzers/corpora/commit_graph/42b4e5430b2b1b17a361067fb9dd33ab74e52232 b/fuzzers/corpora/commit_graph/42b4e5430b2b1b17a361067fb9dd33ab74e52232
new file mode 100644 (file)
index 0000000..6adf001
Binary files /dev/null and b/fuzzers/corpora/commit_graph/42b4e5430b2b1b17a361067fb9dd33ab74e52232 differ
diff --git a/fuzzers/corpora/commit_graph/42ef1c9d234b90acaf1651d930fc52d5f8f158f2 b/fuzzers/corpora/commit_graph/42ef1c9d234b90acaf1651d930fc52d5f8f158f2
new file mode 100644 (file)
index 0000000..0514ae8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/42ef1c9d234b90acaf1651d930fc52d5f8f158f2 differ
diff --git a/fuzzers/corpora/commit_graph/4570c8ff26d7f31afe73b3d9a35a29bc1274d68a b/fuzzers/corpora/commit_graph/4570c8ff26d7f31afe73b3d9a35a29bc1274d68a
new file mode 100644 (file)
index 0000000..834d62b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4570c8ff26d7f31afe73b3d9a35a29bc1274d68a differ
diff --git a/fuzzers/corpora/commit_graph/45cf4751a5929930a7c30ec10134434b9ee13c3d b/fuzzers/corpora/commit_graph/45cf4751a5929930a7c30ec10134434b9ee13c3d
new file mode 100644 (file)
index 0000000..b761279
Binary files /dev/null and b/fuzzers/corpora/commit_graph/45cf4751a5929930a7c30ec10134434b9ee13c3d differ
diff --git a/fuzzers/corpora/commit_graph/46e9d351dd5bb71f7d4d8f15b3fad312c781452e b/fuzzers/corpora/commit_graph/46e9d351dd5bb71f7d4d8f15b3fad312c781452e
new file mode 100644 (file)
index 0000000..ce26235
Binary files /dev/null and b/fuzzers/corpora/commit_graph/46e9d351dd5bb71f7d4d8f15b3fad312c781452e differ
diff --git a/fuzzers/corpora/commit_graph/472421633b984556b96bc20f1fcf7a98c25736f3 b/fuzzers/corpora/commit_graph/472421633b984556b96bc20f1fcf7a98c25736f3
new file mode 100644 (file)
index 0000000..4a2faa1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/472421633b984556b96bc20f1fcf7a98c25736f3 differ
diff --git a/fuzzers/corpora/commit_graph/47f35b91699caee098cacdde0161ffab21bdfc57 b/fuzzers/corpora/commit_graph/47f35b91699caee098cacdde0161ffab21bdfc57
new file mode 100644 (file)
index 0000000..a0f24ef
Binary files /dev/null and b/fuzzers/corpora/commit_graph/47f35b91699caee098cacdde0161ffab21bdfc57 differ
diff --git a/fuzzers/corpora/commit_graph/48b9da327218f9409287687a43b7eead4789a588 b/fuzzers/corpora/commit_graph/48b9da327218f9409287687a43b7eead4789a588
new file mode 100644 (file)
index 0000000..c6f2b79
Binary files /dev/null and b/fuzzers/corpora/commit_graph/48b9da327218f9409287687a43b7eead4789a588 differ
diff --git a/fuzzers/corpora/commit_graph/48d14fca326d5d591d18d34c2821a457277819a2 b/fuzzers/corpora/commit_graph/48d14fca326d5d591d18d34c2821a457277819a2
new file mode 100644 (file)
index 0000000..d223341
Binary files /dev/null and b/fuzzers/corpora/commit_graph/48d14fca326d5d591d18d34c2821a457277819a2 differ
diff --git a/fuzzers/corpora/commit_graph/48f3a33e2a027f5735d0a333ec4acd5a2aa57118 b/fuzzers/corpora/commit_graph/48f3a33e2a027f5735d0a333ec4acd5a2aa57118
new file mode 100644 (file)
index 0000000..0604edb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/48f3a33e2a027f5735d0a333ec4acd5a2aa57118 differ
diff --git a/fuzzers/corpora/commit_graph/49e0eee24eab094a9c62f6b37b6ba01f8aece4e4 b/fuzzers/corpora/commit_graph/49e0eee24eab094a9c62f6b37b6ba01f8aece4e4
new file mode 100644 (file)
index 0000000..78f9425
Binary files /dev/null and b/fuzzers/corpora/commit_graph/49e0eee24eab094a9c62f6b37b6ba01f8aece4e4 differ
diff --git a/fuzzers/corpora/commit_graph/4b45bcb707d2a0bc23b415e9bc3d7eb1f7f0e188 b/fuzzers/corpora/commit_graph/4b45bcb707d2a0bc23b415e9bc3d7eb1f7f0e188
new file mode 100644 (file)
index 0000000..3a1fdd7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4b45bcb707d2a0bc23b415e9bc3d7eb1f7f0e188 differ
diff --git a/fuzzers/corpora/commit_graph/4c428300fe4866fe81cff02ad4bc14b6848f7f73 b/fuzzers/corpora/commit_graph/4c428300fe4866fe81cff02ad4bc14b6848f7f73
new file mode 100644 (file)
index 0000000..d7f09e3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4c428300fe4866fe81cff02ad4bc14b6848f7f73 differ
diff --git a/fuzzers/corpora/commit_graph/4d69c567df2e858c5f248b3fc8e4a9c04f02481c b/fuzzers/corpora/commit_graph/4d69c567df2e858c5f248b3fc8e4a9c04f02481c
new file mode 100644 (file)
index 0000000..26ba525
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4d69c567df2e858c5f248b3fc8e4a9c04f02481c differ
diff --git a/fuzzers/corpora/commit_graph/4d88b6c9b513d5db2e07313a39b43d112d3d4562 b/fuzzers/corpora/commit_graph/4d88b6c9b513d5db2e07313a39b43d112d3d4562
new file mode 100644 (file)
index 0000000..bfe64c9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4d88b6c9b513d5db2e07313a39b43d112d3d4562 differ
diff --git a/fuzzers/corpora/commit_graph/4da73370cf854ef8bd08c7f79b92a187cdbff278 b/fuzzers/corpora/commit_graph/4da73370cf854ef8bd08c7f79b92a187cdbff278
new file mode 100644 (file)
index 0000000..da1801e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4da73370cf854ef8bd08c7f79b92a187cdbff278 differ
diff --git a/fuzzers/corpora/commit_graph/4e4b2827351bbfd414b718052a8f950a9e3eb7ee b/fuzzers/corpora/commit_graph/4e4b2827351bbfd414b718052a8f950a9e3eb7ee
new file mode 100644 (file)
index 0000000..77d2e78
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4e4b2827351bbfd414b718052a8f950a9e3eb7ee differ
diff --git a/fuzzers/corpora/commit_graph/4ed43f7d3c0305461edcbc86f62e0c6ad56df01e b/fuzzers/corpora/commit_graph/4ed43f7d3c0305461edcbc86f62e0c6ad56df01e
new file mode 100644 (file)
index 0000000..cfef7a1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4ed43f7d3c0305461edcbc86f62e0c6ad56df01e differ
diff --git a/fuzzers/corpora/commit_graph/4f011529809e88205421fa8ce39dcc025293bcb8 b/fuzzers/corpora/commit_graph/4f011529809e88205421fa8ce39dcc025293bcb8
new file mode 100644 (file)
index 0000000..2331acf
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4f011529809e88205421fa8ce39dcc025293bcb8 differ
diff --git a/fuzzers/corpora/commit_graph/4f1928b6376369ab6acf8a282284366cc3bf71ef b/fuzzers/corpora/commit_graph/4f1928b6376369ab6acf8a282284366cc3bf71ef
new file mode 100644 (file)
index 0000000..ad3d173
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4f1928b6376369ab6acf8a282284366cc3bf71ef differ
diff --git a/fuzzers/corpora/commit_graph/4f669eca3416c44f0d003ef2720d03e697e2230e b/fuzzers/corpora/commit_graph/4f669eca3416c44f0d003ef2720d03e697e2230e
new file mode 100644 (file)
index 0000000..6a143b3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4f669eca3416c44f0d003ef2720d03e697e2230e differ
diff --git a/fuzzers/corpora/commit_graph/4f750f24ecb5080bea2845061cfd3ce4529d30ee b/fuzzers/corpora/commit_graph/4f750f24ecb5080bea2845061cfd3ce4529d30ee
new file mode 100644 (file)
index 0000000..ea36bdc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4f750f24ecb5080bea2845061cfd3ce4529d30ee differ
diff --git a/fuzzers/corpora/commit_graph/4fab9bb2bacf562e65f4a8681c429e6ea92aaed7 b/fuzzers/corpora/commit_graph/4fab9bb2bacf562e65f4a8681c429e6ea92aaed7
new file mode 100644 (file)
index 0000000..d00a794
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4fab9bb2bacf562e65f4a8681c429e6ea92aaed7 differ
diff --git a/fuzzers/corpora/commit_graph/4fd757c7251c17413b3005fb38aee0fd029d89ec b/fuzzers/corpora/commit_graph/4fd757c7251c17413b3005fb38aee0fd029d89ec
new file mode 100644 (file)
index 0000000..4f4db7d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/4fd757c7251c17413b3005fb38aee0fd029d89ec differ
diff --git a/fuzzers/corpora/commit_graph/506092de91dcf93254cdd5ad9e02a953a38099ea b/fuzzers/corpora/commit_graph/506092de91dcf93254cdd5ad9e02a953a38099ea
new file mode 100644 (file)
index 0000000..64c5405
Binary files /dev/null and b/fuzzers/corpora/commit_graph/506092de91dcf93254cdd5ad9e02a953a38099ea differ
diff --git a/fuzzers/corpora/commit_graph/50e934fb52d9bc5cd2a531adced1cad7f102a112 b/fuzzers/corpora/commit_graph/50e934fb52d9bc5cd2a531adced1cad7f102a112
new file mode 100644 (file)
index 0000000..b630179
Binary files /dev/null and b/fuzzers/corpora/commit_graph/50e934fb52d9bc5cd2a531adced1cad7f102a112 differ
diff --git a/fuzzers/corpora/commit_graph/512e49a9e789656964988950009e6534907e6317 b/fuzzers/corpora/commit_graph/512e49a9e789656964988950009e6534907e6317
new file mode 100644 (file)
index 0000000..7cf8e31
Binary files /dev/null and b/fuzzers/corpora/commit_graph/512e49a9e789656964988950009e6534907e6317 differ
diff --git a/fuzzers/corpora/commit_graph/51404149f1ea30ee6959fafe81a52acabed97e9e b/fuzzers/corpora/commit_graph/51404149f1ea30ee6959fafe81a52acabed97e9e
new file mode 100644 (file)
index 0000000..394e4bf
Binary files /dev/null and b/fuzzers/corpora/commit_graph/51404149f1ea30ee6959fafe81a52acabed97e9e differ
diff --git a/fuzzers/corpora/commit_graph/5150f8a67399ee16178a2b08198cf91a90c0e53e b/fuzzers/corpora/commit_graph/5150f8a67399ee16178a2b08198cf91a90c0e53e
new file mode 100644 (file)
index 0000000..c0867a0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5150f8a67399ee16178a2b08198cf91a90c0e53e differ
diff --git a/fuzzers/corpora/commit_graph/51a1fd23dfe5a8062cd4601d235509247f3bc2dc b/fuzzers/corpora/commit_graph/51a1fd23dfe5a8062cd4601d235509247f3bc2dc
new file mode 100644 (file)
index 0000000..c448928
Binary files /dev/null and b/fuzzers/corpora/commit_graph/51a1fd23dfe5a8062cd4601d235509247f3bc2dc differ
diff --git a/fuzzers/corpora/commit_graph/51a963486f041a60c422f0dd6da3b69c52f12fb7 b/fuzzers/corpora/commit_graph/51a963486f041a60c422f0dd6da3b69c52f12fb7
new file mode 100644 (file)
index 0000000..f8a1c56
Binary files /dev/null and b/fuzzers/corpora/commit_graph/51a963486f041a60c422f0dd6da3b69c52f12fb7 differ
diff --git a/fuzzers/corpora/commit_graph/51fbf57a2a35ec33164838fa254fe605a3c868e9 b/fuzzers/corpora/commit_graph/51fbf57a2a35ec33164838fa254fe605a3c868e9
new file mode 100644 (file)
index 0000000..d0c77cd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/51fbf57a2a35ec33164838fa254fe605a3c868e9 differ
diff --git a/fuzzers/corpora/commit_graph/53068b9f9cb54bb52d076e9602ccd55f169ef39a b/fuzzers/corpora/commit_graph/53068b9f9cb54bb52d076e9602ccd55f169ef39a
new file mode 100644 (file)
index 0000000..bed0af6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/53068b9f9cb54bb52d076e9602ccd55f169ef39a differ
diff --git a/fuzzers/corpora/commit_graph/5314619e15fa5ee67df44481b8213a53786d39c5 b/fuzzers/corpora/commit_graph/5314619e15fa5ee67df44481b8213a53786d39c5
new file mode 100644 (file)
index 0000000..a00e14d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5314619e15fa5ee67df44481b8213a53786d39c5 differ
diff --git a/fuzzers/corpora/commit_graph/533f5f00275968129846522fe01e2819746272eb b/fuzzers/corpora/commit_graph/533f5f00275968129846522fe01e2819746272eb
new file mode 100644 (file)
index 0000000..0830b01
Binary files /dev/null and b/fuzzers/corpora/commit_graph/533f5f00275968129846522fe01e2819746272eb differ
diff --git a/fuzzers/corpora/commit_graph/53a62799135c282435a17e032deda03eaf9daf0f b/fuzzers/corpora/commit_graph/53a62799135c282435a17e032deda03eaf9daf0f
new file mode 100644 (file)
index 0000000..f6bfddb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/53a62799135c282435a17e032deda03eaf9daf0f differ
diff --git a/fuzzers/corpora/commit_graph/53c9d5cd849977e523d92dd2d639e9b0e721be50 b/fuzzers/corpora/commit_graph/53c9d5cd849977e523d92dd2d639e9b0e721be50
new file mode 100644 (file)
index 0000000..ed30c5e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/53c9d5cd849977e523d92dd2d639e9b0e721be50 differ
diff --git a/fuzzers/corpora/commit_graph/54767a0bb3b96d39f5b2004ce3f274465f1a927e b/fuzzers/corpora/commit_graph/54767a0bb3b96d39f5b2004ce3f274465f1a927e
new file mode 100644 (file)
index 0000000..fd9a0ac
Binary files /dev/null and b/fuzzers/corpora/commit_graph/54767a0bb3b96d39f5b2004ce3f274465f1a927e differ
diff --git a/fuzzers/corpora/commit_graph/548de37dbe6a3829b73d976996ec9838cf608554 b/fuzzers/corpora/commit_graph/548de37dbe6a3829b73d976996ec9838cf608554
new file mode 100644 (file)
index 0000000..89772e2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/548de37dbe6a3829b73d976996ec9838cf608554 differ
diff --git a/fuzzers/corpora/commit_graph/5522cefa54b798ea4aba8ef2a42ad248a7fb02ee b/fuzzers/corpora/commit_graph/5522cefa54b798ea4aba8ef2a42ad248a7fb02ee
new file mode 100644 (file)
index 0000000..6a4da78
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5522cefa54b798ea4aba8ef2a42ad248a7fb02ee differ
diff --git a/fuzzers/corpora/commit_graph/554fab3eef5d8709f06d1d4319efe5c0c437421b b/fuzzers/corpora/commit_graph/554fab3eef5d8709f06d1d4319efe5c0c437421b
new file mode 100644 (file)
index 0000000..7a54bd0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/554fab3eef5d8709f06d1d4319efe5c0c437421b differ
diff --git a/fuzzers/corpora/commit_graph/567fe73919dae39b0bcb78b03d655643a71714a8 b/fuzzers/corpora/commit_graph/567fe73919dae39b0bcb78b03d655643a71714a8
new file mode 100644 (file)
index 0000000..56b1e14
Binary files /dev/null and b/fuzzers/corpora/commit_graph/567fe73919dae39b0bcb78b03d655643a71714a8 differ
diff --git a/fuzzers/corpora/commit_graph/5717a281aa722ee4a32dfa1cc72fc5d6081f6755 b/fuzzers/corpora/commit_graph/5717a281aa722ee4a32dfa1cc72fc5d6081f6755
new file mode 100644 (file)
index 0000000..77f0e51
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5717a281aa722ee4a32dfa1cc72fc5d6081f6755 differ
diff --git a/fuzzers/corpora/commit_graph/577d814e0be43df9321c5b27119c398bd00a00c5 b/fuzzers/corpora/commit_graph/577d814e0be43df9321c5b27119c398bd00a00c5
new file mode 100644 (file)
index 0000000..c892728
Binary files /dev/null and b/fuzzers/corpora/commit_graph/577d814e0be43df9321c5b27119c398bd00a00c5 differ
diff --git a/fuzzers/corpora/commit_graph/58680611707c6188f9f067f8747b699cd2fe82d3 b/fuzzers/corpora/commit_graph/58680611707c6188f9f067f8747b699cd2fe82d3
new file mode 100644 (file)
index 0000000..81efaf3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/58680611707c6188f9f067f8747b699cd2fe82d3 differ
diff --git a/fuzzers/corpora/commit_graph/5915b7f91dd43ec37a4718061c90cbec2686b916 b/fuzzers/corpora/commit_graph/5915b7f91dd43ec37a4718061c90cbec2686b916
new file mode 100644 (file)
index 0000000..f22d2aa
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5915b7f91dd43ec37a4718061c90cbec2686b916 differ
diff --git a/fuzzers/corpora/commit_graph/599516e368ff621dd06d8450837350f4e9558c38 b/fuzzers/corpora/commit_graph/599516e368ff621dd06d8450837350f4e9558c38
new file mode 100644 (file)
index 0000000..6aff8ee
Binary files /dev/null and b/fuzzers/corpora/commit_graph/599516e368ff621dd06d8450837350f4e9558c38 differ
diff --git a/fuzzers/corpora/commit_graph/5a2d01d141e4d523e718c30e20cb07c3ad98f33d b/fuzzers/corpora/commit_graph/5a2d01d141e4d523e718c30e20cb07c3ad98f33d
new file mode 100644 (file)
index 0000000..fb20c58
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5a2d01d141e4d523e718c30e20cb07c3ad98f33d differ
diff --git a/fuzzers/corpora/commit_graph/5a9803ef8cd88d1e8f1d6e5920b8afd170cafb11 b/fuzzers/corpora/commit_graph/5a9803ef8cd88d1e8f1d6e5920b8afd170cafb11
new file mode 100644 (file)
index 0000000..38c2c08
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5a9803ef8cd88d1e8f1d6e5920b8afd170cafb11 differ
diff --git a/fuzzers/corpora/commit_graph/5ba93c9db0cff93f52b521d7420e43f6eda2784f b/fuzzers/corpora/commit_graph/5ba93c9db0cff93f52b521d7420e43f6eda2784f
new file mode 100644 (file)
index 0000000..f76dd23
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5ba93c9db0cff93f52b521d7420e43f6eda2784f differ
diff --git a/fuzzers/corpora/commit_graph/5bf0ca772092e6fa34b6822f61a1b1c3d7f2c6e3 b/fuzzers/corpora/commit_graph/5bf0ca772092e6fa34b6822f61a1b1c3d7f2c6e3
new file mode 100644 (file)
index 0000000..06dd1e1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5bf0ca772092e6fa34b6822f61a1b1c3d7f2c6e3 differ
diff --git a/fuzzers/corpora/commit_graph/5cfbfb3e12b629dc9f74baf0a8741345ec288795 b/fuzzers/corpora/commit_graph/5cfbfb3e12b629dc9f74baf0a8741345ec288795
new file mode 100644 (file)
index 0000000..73e257d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5cfbfb3e12b629dc9f74baf0a8741345ec288795 differ
diff --git a/fuzzers/corpora/commit_graph/5d8cc97b739c39820b761b6551d34dd647da6816 b/fuzzers/corpora/commit_graph/5d8cc97b739c39820b761b6551d34dd647da6816
new file mode 100644 (file)
index 0000000..7a241f3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5d8cc97b739c39820b761b6551d34dd647da6816 differ
diff --git a/fuzzers/corpora/commit_graph/5dcbb3e1c2fc9a191dd3f3443b86f6bc38c39e37 b/fuzzers/corpora/commit_graph/5dcbb3e1c2fc9a191dd3f3443b86f6bc38c39e37
new file mode 100644 (file)
index 0000000..04a1639
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5dcbb3e1c2fc9a191dd3f3443b86f6bc38c39e37 differ
diff --git a/fuzzers/corpora/commit_graph/5ec17d081aef9872f746e88ad8b03553719f9c36 b/fuzzers/corpora/commit_graph/5ec17d081aef9872f746e88ad8b03553719f9c36
new file mode 100644 (file)
index 0000000..84fa131
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5ec17d081aef9872f746e88ad8b03553719f9c36 differ
diff --git a/fuzzers/corpora/commit_graph/5f88e3ba60c11be25c47a842763d8870d23cc7f2 b/fuzzers/corpora/commit_graph/5f88e3ba60c11be25c47a842763d8870d23cc7f2
new file mode 100644 (file)
index 0000000..3669387
Binary files /dev/null and b/fuzzers/corpora/commit_graph/5f88e3ba60c11be25c47a842763d8870d23cc7f2 differ
diff --git a/fuzzers/corpora/commit_graph/6045e4d2bf85013c78a32e71b014ba3d4a4b7c61 b/fuzzers/corpora/commit_graph/6045e4d2bf85013c78a32e71b014ba3d4a4b7c61
new file mode 100644 (file)
index 0000000..5ebec5a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6045e4d2bf85013c78a32e71b014ba3d4a4b7c61 differ
diff --git a/fuzzers/corpora/commit_graph/615c7ba7ffbce955ffd964682e2a0f7ef3c767e4 b/fuzzers/corpora/commit_graph/615c7ba7ffbce955ffd964682e2a0f7ef3c767e4
new file mode 100644 (file)
index 0000000..8360672
Binary files /dev/null and b/fuzzers/corpora/commit_graph/615c7ba7ffbce955ffd964682e2a0f7ef3c767e4 differ
diff --git a/fuzzers/corpora/commit_graph/6189f29cbbe88ac6cb32fdefecda1bd6194332a6 b/fuzzers/corpora/commit_graph/6189f29cbbe88ac6cb32fdefecda1bd6194332a6
new file mode 100644 (file)
index 0000000..40ec5b1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6189f29cbbe88ac6cb32fdefecda1bd6194332a6 differ
diff --git a/fuzzers/corpora/commit_graph/627224cb8484c62992dcbc4cdebdbfa48a3c021a b/fuzzers/corpora/commit_graph/627224cb8484c62992dcbc4cdebdbfa48a3c021a
new file mode 100644 (file)
index 0000000..f73b59d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/627224cb8484c62992dcbc4cdebdbfa48a3c021a differ
diff --git a/fuzzers/corpora/commit_graph/629fff0962d298a7283a3d1e1d1b940dfef9b315 b/fuzzers/corpora/commit_graph/629fff0962d298a7283a3d1e1d1b940dfef9b315
new file mode 100644 (file)
index 0000000..1c0c2c4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/629fff0962d298a7283a3d1e1d1b940dfef9b315 differ
diff --git a/fuzzers/corpora/commit_graph/6322594cff2a99d0abb1139e6a43b06df76d539a b/fuzzers/corpora/commit_graph/6322594cff2a99d0abb1139e6a43b06df76d539a
new file mode 100644 (file)
index 0000000..4dabbce
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6322594cff2a99d0abb1139e6a43b06df76d539a differ
diff --git a/fuzzers/corpora/commit_graph/63de5e8e042222d53bf05640c87da376aefb76cc b/fuzzers/corpora/commit_graph/63de5e8e042222d53bf05640c87da376aefb76cc
new file mode 100644 (file)
index 0000000..2fd95a3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/63de5e8e042222d53bf05640c87da376aefb76cc differ
diff --git a/fuzzers/corpora/commit_graph/647dbb1d05fe0fab685bfe126bd9ac3a12b6bccf b/fuzzers/corpora/commit_graph/647dbb1d05fe0fab685bfe126bd9ac3a12b6bccf
new file mode 100644 (file)
index 0000000..245d46b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/647dbb1d05fe0fab685bfe126bd9ac3a12b6bccf differ
diff --git a/fuzzers/corpora/commit_graph/647e5e265d8d1079784fc2a3da25f7ba58126acd b/fuzzers/corpora/commit_graph/647e5e265d8d1079784fc2a3da25f7ba58126acd
new file mode 100644 (file)
index 0000000..633a2a3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/647e5e265d8d1079784fc2a3da25f7ba58126acd differ
diff --git a/fuzzers/corpora/commit_graph/653bd480dfd1e5f4bdca702aba3dfd8da0c204b7 b/fuzzers/corpora/commit_graph/653bd480dfd1e5f4bdca702aba3dfd8da0c204b7
new file mode 100644 (file)
index 0000000..d123602
Binary files /dev/null and b/fuzzers/corpora/commit_graph/653bd480dfd1e5f4bdca702aba3dfd8da0c204b7 differ
diff --git a/fuzzers/corpora/commit_graph/65485740a465377213c80fa68028727f281299fb b/fuzzers/corpora/commit_graph/65485740a465377213c80fa68028727f281299fb
new file mode 100644 (file)
index 0000000..c100bdb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/65485740a465377213c80fa68028727f281299fb differ
diff --git a/fuzzers/corpora/commit_graph/6551f8c8c3028006d0cc4997943df8a86ee3f598 b/fuzzers/corpora/commit_graph/6551f8c8c3028006d0cc4997943df8a86ee3f598
new file mode 100644 (file)
index 0000000..0ff4dda
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6551f8c8c3028006d0cc4997943df8a86ee3f598 differ
diff --git a/fuzzers/corpora/commit_graph/67799e79d33883510f85ae9705ab3932862128a2 b/fuzzers/corpora/commit_graph/67799e79d33883510f85ae9705ab3932862128a2
new file mode 100644 (file)
index 0000000..2782b4f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/67799e79d33883510f85ae9705ab3932862128a2 differ
diff --git a/fuzzers/corpora/commit_graph/67b475481e5a21351b49789874adbc988aefd64c b/fuzzers/corpora/commit_graph/67b475481e5a21351b49789874adbc988aefd64c
new file mode 100644 (file)
index 0000000..263753a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/67b475481e5a21351b49789874adbc988aefd64c differ
diff --git a/fuzzers/corpora/commit_graph/67e5a649967dee002d1c181e079748c404e29767 b/fuzzers/corpora/commit_graph/67e5a649967dee002d1c181e079748c404e29767
new file mode 100644 (file)
index 0000000..3bb8714
Binary files /dev/null and b/fuzzers/corpora/commit_graph/67e5a649967dee002d1c181e079748c404e29767 differ
diff --git a/fuzzers/corpora/commit_graph/687424a4a31a66a78d1637c680c9c10746741007 b/fuzzers/corpora/commit_graph/687424a4a31a66a78d1637c680c9c10746741007
new file mode 100644 (file)
index 0000000..6b26c19
Binary files /dev/null and b/fuzzers/corpora/commit_graph/687424a4a31a66a78d1637c680c9c10746741007 differ
diff --git a/fuzzers/corpora/commit_graph/68fa6dd52832657cb8dd7e1485d6fbafd4e93903 b/fuzzers/corpora/commit_graph/68fa6dd52832657cb8dd7e1485d6fbafd4e93903
new file mode 100644 (file)
index 0000000..fb966ff
Binary files /dev/null and b/fuzzers/corpora/commit_graph/68fa6dd52832657cb8dd7e1485d6fbafd4e93903 differ
diff --git a/fuzzers/corpora/commit_graph/691696af1c042115f4d9f9b8e24f7b8c06ed189b b/fuzzers/corpora/commit_graph/691696af1c042115f4d9f9b8e24f7b8c06ed189b
new file mode 100644 (file)
index 0000000..e407bd3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/691696af1c042115f4d9f9b8e24f7b8c06ed189b differ
diff --git a/fuzzers/corpora/commit_graph/6a80152f9b1afa3a3080bf3f6aa48e84c2e18497 b/fuzzers/corpora/commit_graph/6a80152f9b1afa3a3080bf3f6aa48e84c2e18497
new file mode 100644 (file)
index 0000000..a706cb0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6a80152f9b1afa3a3080bf3f6aa48e84c2e18497 differ
diff --git a/fuzzers/corpora/commit_graph/6af27e4cf4c7bcce128a5949ee27fc73ab2cc71e b/fuzzers/corpora/commit_graph/6af27e4cf4c7bcce128a5949ee27fc73ab2cc71e
new file mode 100644 (file)
index 0000000..d0b2fd2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6af27e4cf4c7bcce128a5949ee27fc73ab2cc71e differ
diff --git a/fuzzers/corpora/commit_graph/6afd8f82d5639b774de0dfd418ae85322f4168dd b/fuzzers/corpora/commit_graph/6afd8f82d5639b774de0dfd418ae85322f4168dd
new file mode 100644 (file)
index 0000000..7840c31
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6afd8f82d5639b774de0dfd418ae85322f4168dd differ
diff --git a/fuzzers/corpora/commit_graph/6c64a9e26e0e1480bb5e60b7044ca6ce17104a80 b/fuzzers/corpora/commit_graph/6c64a9e26e0e1480bb5e60b7044ca6ce17104a80
new file mode 100644 (file)
index 0000000..752046b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6c64a9e26e0e1480bb5e60b7044ca6ce17104a80 differ
diff --git a/fuzzers/corpora/commit_graph/6c850c17db130ca0152f7c75562fa191f7ef89de b/fuzzers/corpora/commit_graph/6c850c17db130ca0152f7c75562fa191f7ef89de
new file mode 100644 (file)
index 0000000..a7f693b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6c850c17db130ca0152f7c75562fa191f7ef89de differ
diff --git a/fuzzers/corpora/commit_graph/6c9afe4527371a2baf33c5e220e4ca21a3207f94 b/fuzzers/corpora/commit_graph/6c9afe4527371a2baf33c5e220e4ca21a3207f94
new file mode 100644 (file)
index 0000000..d7b8ffc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6c9afe4527371a2baf33c5e220e4ca21a3207f94 differ
diff --git a/fuzzers/corpora/commit_graph/6ce3d40b0225923a7f4123a919b1c5d70841fad7 b/fuzzers/corpora/commit_graph/6ce3d40b0225923a7f4123a919b1c5d70841fad7
new file mode 100644 (file)
index 0000000..3a2836b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6ce3d40b0225923a7f4123a919b1c5d70841fad7 differ
diff --git a/fuzzers/corpora/commit_graph/6cfd064aa6197813eb18f38df967ae4cdba9c6da b/fuzzers/corpora/commit_graph/6cfd064aa6197813eb18f38df967ae4cdba9c6da
new file mode 100644 (file)
index 0000000..51778d5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6cfd064aa6197813eb18f38df967ae4cdba9c6da differ
diff --git a/fuzzers/corpora/commit_graph/6e6675676c53bcddc870e06605d2432e3429f224 b/fuzzers/corpora/commit_graph/6e6675676c53bcddc870e06605d2432e3429f224
new file mode 100644 (file)
index 0000000..1ddebef
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6e6675676c53bcddc870e06605d2432e3429f224 differ
diff --git a/fuzzers/corpora/commit_graph/6e6e82579b7abae2b43d90448d3f2ead4dfcba78 b/fuzzers/corpora/commit_graph/6e6e82579b7abae2b43d90448d3f2ead4dfcba78
new file mode 100644 (file)
index 0000000..a528901
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6e6e82579b7abae2b43d90448d3f2ead4dfcba78 differ
diff --git a/fuzzers/corpora/commit_graph/6f13d23c75a562eddefafe85e208e602832294e2 b/fuzzers/corpora/commit_graph/6f13d23c75a562eddefafe85e208e602832294e2
new file mode 100644 (file)
index 0000000..49a5393
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6f13d23c75a562eddefafe85e208e602832294e2 differ
diff --git a/fuzzers/corpora/commit_graph/6fed59b0472927f5d2396d0ee4d7fd13579377ce b/fuzzers/corpora/commit_graph/6fed59b0472927f5d2396d0ee4d7fd13579377ce
new file mode 100644 (file)
index 0000000..6b3970f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/6fed59b0472927f5d2396d0ee4d7fd13579377ce differ
diff --git a/fuzzers/corpora/commit_graph/71f7724196f9f8fcfe3ee0161a84893bb9c4ab11 b/fuzzers/corpora/commit_graph/71f7724196f9f8fcfe3ee0161a84893bb9c4ab11
new file mode 100644 (file)
index 0000000..9e5c8dd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/71f7724196f9f8fcfe3ee0161a84893bb9c4ab11 differ
diff --git a/fuzzers/corpora/commit_graph/7335ecb1d41e713bf3909adf5802b90e22bc1581 b/fuzzers/corpora/commit_graph/7335ecb1d41e713bf3909adf5802b90e22bc1581
new file mode 100644 (file)
index 0000000..02e2fa6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7335ecb1d41e713bf3909adf5802b90e22bc1581 differ
diff --git a/fuzzers/corpora/commit_graph/73afaa73175f461e1d19d5138e055c1649926dfe b/fuzzers/corpora/commit_graph/73afaa73175f461e1d19d5138e055c1649926dfe
new file mode 100644 (file)
index 0000000..0f45e0b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/73afaa73175f461e1d19d5138e055c1649926dfe differ
diff --git a/fuzzers/corpora/commit_graph/73e2fcb45c4df90d19091056b235e7a317631a62 b/fuzzers/corpora/commit_graph/73e2fcb45c4df90d19091056b235e7a317631a62
new file mode 100644 (file)
index 0000000..549eeb3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/73e2fcb45c4df90d19091056b235e7a317631a62 differ
diff --git a/fuzzers/corpora/commit_graph/741cb2d5ae11b0a9e0608b58ec7284d75129a1f2 b/fuzzers/corpora/commit_graph/741cb2d5ae11b0a9e0608b58ec7284d75129a1f2
new file mode 100644 (file)
index 0000000..a16738d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/741cb2d5ae11b0a9e0608b58ec7284d75129a1f2 differ
diff --git a/fuzzers/corpora/commit_graph/7431bb0097a9bb52e1ceaaa8674a13cd3486a387 b/fuzzers/corpora/commit_graph/7431bb0097a9bb52e1ceaaa8674a13cd3486a387
new file mode 100644 (file)
index 0000000..d681b26
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7431bb0097a9bb52e1ceaaa8674a13cd3486a387 differ
diff --git a/fuzzers/corpora/commit_graph/7455b805995d0c96ac12f8a1c1264caaffcfac1c b/fuzzers/corpora/commit_graph/7455b805995d0c96ac12f8a1c1264caaffcfac1c
new file mode 100644 (file)
index 0000000..b3d2620
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7455b805995d0c96ac12f8a1c1264caaffcfac1c differ
diff --git a/fuzzers/corpora/commit_graph/74e39b8a82fc06f9ed8f83ea30545ddf6df66811 b/fuzzers/corpora/commit_graph/74e39b8a82fc06f9ed8f83ea30545ddf6df66811
new file mode 100644 (file)
index 0000000..3cc9deb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/74e39b8a82fc06f9ed8f83ea30545ddf6df66811 differ
diff --git a/fuzzers/corpora/commit_graph/75d51e413d3e916560dc0c2ee5092d2f4972aec1 b/fuzzers/corpora/commit_graph/75d51e413d3e916560dc0c2ee5092d2f4972aec1
new file mode 100644 (file)
index 0000000..68f34e7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/75d51e413d3e916560dc0c2ee5092d2f4972aec1 differ
diff --git a/fuzzers/corpora/commit_graph/75e068964ea6beb7310a154d763de74a70071f48 b/fuzzers/corpora/commit_graph/75e068964ea6beb7310a154d763de74a70071f48
new file mode 100644 (file)
index 0000000..a08ee58
Binary files /dev/null and b/fuzzers/corpora/commit_graph/75e068964ea6beb7310a154d763de74a70071f48 differ
diff --git a/fuzzers/corpora/commit_graph/763bf498dd847bd2b4af7b611199619bd428bea6 b/fuzzers/corpora/commit_graph/763bf498dd847bd2b4af7b611199619bd428bea6
new file mode 100644 (file)
index 0000000..4c28935
Binary files /dev/null and b/fuzzers/corpora/commit_graph/763bf498dd847bd2b4af7b611199619bd428bea6 differ
diff --git a/fuzzers/corpora/commit_graph/77064ae04581a3c6d2a77158ef1a0b1e60db414a b/fuzzers/corpora/commit_graph/77064ae04581a3c6d2a77158ef1a0b1e60db414a
new file mode 100644 (file)
index 0000000..fbd0ca7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/77064ae04581a3c6d2a77158ef1a0b1e60db414a differ
diff --git a/fuzzers/corpora/commit_graph/783bb14d68021061f592601607f40fe232ad17c4 b/fuzzers/corpora/commit_graph/783bb14d68021061f592601607f40fe232ad17c4
new file mode 100644 (file)
index 0000000..3cfa562
Binary files /dev/null and b/fuzzers/corpora/commit_graph/783bb14d68021061f592601607f40fe232ad17c4 differ
diff --git a/fuzzers/corpora/commit_graph/7862814cb684310b54ef920b35403515efaba13c b/fuzzers/corpora/commit_graph/7862814cb684310b54ef920b35403515efaba13c
new file mode 100644 (file)
index 0000000..3066626
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7862814cb684310b54ef920b35403515efaba13c differ
diff --git a/fuzzers/corpora/commit_graph/791fd85b6ffb2429e9fa5ba29eebdce214ad88c7 b/fuzzers/corpora/commit_graph/791fd85b6ffb2429e9fa5ba29eebdce214ad88c7
new file mode 100644 (file)
index 0000000..2c4739b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/791fd85b6ffb2429e9fa5ba29eebdce214ad88c7 differ
diff --git a/fuzzers/corpora/commit_graph/79396d4f6142a53e26e14aa6ccb4afb4fd8fc580 b/fuzzers/corpora/commit_graph/79396d4f6142a53e26e14aa6ccb4afb4fd8fc580
new file mode 100644 (file)
index 0000000..ef54342
Binary files /dev/null and b/fuzzers/corpora/commit_graph/79396d4f6142a53e26e14aa6ccb4afb4fd8fc580 differ
diff --git a/fuzzers/corpora/commit_graph/79661b8e529e2182d5c612faba9f26e32a122b78 b/fuzzers/corpora/commit_graph/79661b8e529e2182d5c612faba9f26e32a122b78
new file mode 100644 (file)
index 0000000..75ebe29
Binary files /dev/null and b/fuzzers/corpora/commit_graph/79661b8e529e2182d5c612faba9f26e32a122b78 differ
diff --git a/fuzzers/corpora/commit_graph/7969143acb3334bffac46c6dfd96362c81644191 b/fuzzers/corpora/commit_graph/7969143acb3334bffac46c6dfd96362c81644191
new file mode 100644 (file)
index 0000000..6ea2e66
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7969143acb3334bffac46c6dfd96362c81644191 differ
diff --git a/fuzzers/corpora/commit_graph/79d84866dc8c067508c02516b65c0e48cf689b56 b/fuzzers/corpora/commit_graph/79d84866dc8c067508c02516b65c0e48cf689b56
new file mode 100644 (file)
index 0000000..3080da7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/79d84866dc8c067508c02516b65c0e48cf689b56 differ
diff --git a/fuzzers/corpora/commit_graph/7b61f8f4a96e309bbe64ed82637fc81492a9652f b/fuzzers/corpora/commit_graph/7b61f8f4a96e309bbe64ed82637fc81492a9652f
new file mode 100644 (file)
index 0000000..28d93b7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7b61f8f4a96e309bbe64ed82637fc81492a9652f differ
diff --git a/fuzzers/corpora/commit_graph/7b8123f973edfb0f3cab027c0cd6b8efc7b11d6b b/fuzzers/corpora/commit_graph/7b8123f973edfb0f3cab027c0cd6b8efc7b11d6b
new file mode 100644 (file)
index 0000000..1c6699b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7b8123f973edfb0f3cab027c0cd6b8efc7b11d6b differ
diff --git a/fuzzers/corpora/commit_graph/7b8dd3093efba07f7a4d3bab4b90b8f6e4f28bfb b/fuzzers/corpora/commit_graph/7b8dd3093efba07f7a4d3bab4b90b8f6e4f28bfb
new file mode 100644 (file)
index 0000000..3e686e9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7b8dd3093efba07f7a4d3bab4b90b8f6e4f28bfb differ
diff --git a/fuzzers/corpora/commit_graph/7cc771aab0f3be7730881a46d952ae0a06958201 b/fuzzers/corpora/commit_graph/7cc771aab0f3be7730881a46d952ae0a06958201
new file mode 100644 (file)
index 0000000..ba94bfe
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7cc771aab0f3be7730881a46d952ae0a06958201 differ
diff --git a/fuzzers/corpora/commit_graph/7d177f4207de78d50df2493a3bc07f2cd578b363 b/fuzzers/corpora/commit_graph/7d177f4207de78d50df2493a3bc07f2cd578b363
new file mode 100644 (file)
index 0000000..a936354
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7d177f4207de78d50df2493a3bc07f2cd578b363 differ
diff --git a/fuzzers/corpora/commit_graph/7d2df075f3e73ea9809c31586c37ece0f568b7fa b/fuzzers/corpora/commit_graph/7d2df075f3e73ea9809c31586c37ece0f568b7fa
new file mode 100644 (file)
index 0000000..897276b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7d2df075f3e73ea9809c31586c37ece0f568b7fa differ
diff --git a/fuzzers/corpora/commit_graph/7d386e68e4c733a1fb11c0117f379fb4b9955fbb b/fuzzers/corpora/commit_graph/7d386e68e4c733a1fb11c0117f379fb4b9955fbb
new file mode 100644 (file)
index 0000000..f4f4d75
--- /dev/null
@@ -0,0 +1 @@
+\eØúö
\ No newline at end of file
diff --git a/fuzzers/corpora/commit_graph/7e4260830352479d29310bd6e1022e19a68ffe76 b/fuzzers/corpora/commit_graph/7e4260830352479d29310bd6e1022e19a68ffe76
new file mode 100644 (file)
index 0000000..f478389
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7e4260830352479d29310bd6e1022e19a68ffe76 differ
diff --git a/fuzzers/corpora/commit_graph/7e4dfdae52be18cf95555c2eb1f54af7f69c6dde b/fuzzers/corpora/commit_graph/7e4dfdae52be18cf95555c2eb1f54af7f69c6dde
new file mode 100644 (file)
index 0000000..0f6d976
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7e4dfdae52be18cf95555c2eb1f54af7f69c6dde differ
diff --git a/fuzzers/corpora/commit_graph/7eafedf7e7f20e86ecdf9ba51febf8492bdbc1f1 b/fuzzers/corpora/commit_graph/7eafedf7e7f20e86ecdf9ba51febf8492bdbc1f1
new file mode 100644 (file)
index 0000000..ae5f7c5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7eafedf7e7f20e86ecdf9ba51febf8492bdbc1f1 differ
diff --git a/fuzzers/corpora/commit_graph/7ef1829a378d66b1dd70a767729127a0dc5edcae b/fuzzers/corpora/commit_graph/7ef1829a378d66b1dd70a767729127a0dc5edcae
new file mode 100644 (file)
index 0000000..e5d7355
Binary files /dev/null and b/fuzzers/corpora/commit_graph/7ef1829a378d66b1dd70a767729127a0dc5edcae differ
diff --git a/fuzzers/corpora/commit_graph/80b7d2b9d7e8c8fd7ae239b8d307b592f97ee000 b/fuzzers/corpora/commit_graph/80b7d2b9d7e8c8fd7ae239b8d307b592f97ee000
new file mode 100644 (file)
index 0000000..58ddc12
Binary files /dev/null and b/fuzzers/corpora/commit_graph/80b7d2b9d7e8c8fd7ae239b8d307b592f97ee000 differ
diff --git a/fuzzers/corpora/commit_graph/810f577ff5c1af7807a26226af912687558158cd b/fuzzers/corpora/commit_graph/810f577ff5c1af7807a26226af912687558158cd
new file mode 100644 (file)
index 0000000..be8be9c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/810f577ff5c1af7807a26226af912687558158cd differ
diff --git a/fuzzers/corpora/commit_graph/81603f1fe8d8e29005418d0fc9a9b33972366038 b/fuzzers/corpora/commit_graph/81603f1fe8d8e29005418d0fc9a9b33972366038
new file mode 100644 (file)
index 0000000..d9cb488
Binary files /dev/null and b/fuzzers/corpora/commit_graph/81603f1fe8d8e29005418d0fc9a9b33972366038 differ
diff --git a/fuzzers/corpora/commit_graph/81c8b4d6884f954935fa4a8e828c4637db04b61a b/fuzzers/corpora/commit_graph/81c8b4d6884f954935fa4a8e828c4637db04b61a
new file mode 100644 (file)
index 0000000..47ae17b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/81c8b4d6884f954935fa4a8e828c4637db04b61a differ
diff --git a/fuzzers/corpora/commit_graph/8226846e9b092561f85cc2956ab89d8cc1ae61e0 b/fuzzers/corpora/commit_graph/8226846e9b092561f85cc2956ab89d8cc1ae61e0
new file mode 100644 (file)
index 0000000..80d1cd9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8226846e9b092561f85cc2956ab89d8cc1ae61e0 differ
diff --git a/fuzzers/corpora/commit_graph/825cfceea434e2392cce161356e3cb5f81ec2b3a b/fuzzers/corpora/commit_graph/825cfceea434e2392cce161356e3cb5f81ec2b3a
new file mode 100644 (file)
index 0000000..01f87ed
Binary files /dev/null and b/fuzzers/corpora/commit_graph/825cfceea434e2392cce161356e3cb5f81ec2b3a differ
diff --git a/fuzzers/corpora/commit_graph/82603febce83d95adf68b85cabf15d43ca0c4ee9 b/fuzzers/corpora/commit_graph/82603febce83d95adf68b85cabf15d43ca0c4ee9
new file mode 100644 (file)
index 0000000..d828b05
Binary files /dev/null and b/fuzzers/corpora/commit_graph/82603febce83d95adf68b85cabf15d43ca0c4ee9 differ
diff --git a/fuzzers/corpora/commit_graph/827f0826cc4156e19b4c4938bec74e38de62fe9c b/fuzzers/corpora/commit_graph/827f0826cc4156e19b4c4938bec74e38de62fe9c
new file mode 100644 (file)
index 0000000..a391d62
Binary files /dev/null and b/fuzzers/corpora/commit_graph/827f0826cc4156e19b4c4938bec74e38de62fe9c differ
diff --git a/fuzzers/corpora/commit_graph/8486397ff8d1156249676c19b419a7758ff53f9a b/fuzzers/corpora/commit_graph/8486397ff8d1156249676c19b419a7758ff53f9a
new file mode 100644 (file)
index 0000000..dac9bbe
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8486397ff8d1156249676c19b419a7758ff53f9a differ
diff --git a/fuzzers/corpora/commit_graph/84d99ee359bec1b8ee0f59e9bd96f1da062030b7 b/fuzzers/corpora/commit_graph/84d99ee359bec1b8ee0f59e9bd96f1da062030b7
new file mode 100644 (file)
index 0000000..a2e7cf3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/84d99ee359bec1b8ee0f59e9bd96f1da062030b7 differ
diff --git a/fuzzers/corpora/commit_graph/84e629bc7416039f1feb81fa9168d7c1ee3141c2 b/fuzzers/corpora/commit_graph/84e629bc7416039f1feb81fa9168d7c1ee3141c2
new file mode 100644 (file)
index 0000000..8ae4e39
Binary files /dev/null and b/fuzzers/corpora/commit_graph/84e629bc7416039f1feb81fa9168d7c1ee3141c2 differ
diff --git a/fuzzers/corpora/commit_graph/84e885752179076fb38739ca7bc4345716bee56a b/fuzzers/corpora/commit_graph/84e885752179076fb38739ca7bc4345716bee56a
new file mode 100644 (file)
index 0000000..dd0c426
Binary files /dev/null and b/fuzzers/corpora/commit_graph/84e885752179076fb38739ca7bc4345716bee56a differ
diff --git a/fuzzers/corpora/commit_graph/859ef05494c8070057810b5c20df00fc81f81cf5 b/fuzzers/corpora/commit_graph/859ef05494c8070057810b5c20df00fc81f81cf5
new file mode 100644 (file)
index 0000000..2e3f299
Binary files /dev/null and b/fuzzers/corpora/commit_graph/859ef05494c8070057810b5c20df00fc81f81cf5 differ
diff --git a/fuzzers/corpora/commit_graph/859fe592f33abc1d959c0e73ecd6cd4bffe23a97 b/fuzzers/corpora/commit_graph/859fe592f33abc1d959c0e73ecd6cd4bffe23a97
new file mode 100644 (file)
index 0000000..5289c8e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/859fe592f33abc1d959c0e73ecd6cd4bffe23a97 differ
diff --git a/fuzzers/corpora/commit_graph/860da5e8a468805b76a44b9ac99b4575be16ea15 b/fuzzers/corpora/commit_graph/860da5e8a468805b76a44b9ac99b4575be16ea15
new file mode 100644 (file)
index 0000000..c8b03da
Binary files /dev/null and b/fuzzers/corpora/commit_graph/860da5e8a468805b76a44b9ac99b4575be16ea15 differ
diff --git a/fuzzers/corpora/commit_graph/865e415745cead02a826f058a5ee49099bdf9562 b/fuzzers/corpora/commit_graph/865e415745cead02a826f058a5ee49099bdf9562
new file mode 100644 (file)
index 0000000..a4ce658
Binary files /dev/null and b/fuzzers/corpora/commit_graph/865e415745cead02a826f058a5ee49099bdf9562 differ
diff --git a/fuzzers/corpora/commit_graph/878bfce051a9c7462847d4e99b7e926dc821b7b8 b/fuzzers/corpora/commit_graph/878bfce051a9c7462847d4e99b7e926dc821b7b8
new file mode 100644 (file)
index 0000000..efb0bc5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/878bfce051a9c7462847d4e99b7e926dc821b7b8 differ
diff --git a/fuzzers/corpora/commit_graph/880492e4dc7259577c227bb4f075d7165e875c29 b/fuzzers/corpora/commit_graph/880492e4dc7259577c227bb4f075d7165e875c29
new file mode 100644 (file)
index 0000000..c977dff
Binary files /dev/null and b/fuzzers/corpora/commit_graph/880492e4dc7259577c227bb4f075d7165e875c29 differ
diff --git a/fuzzers/corpora/commit_graph/88b7de1bd1c96454a1350286d115c0ee368511f9 b/fuzzers/corpora/commit_graph/88b7de1bd1c96454a1350286d115c0ee368511f9
new file mode 100644 (file)
index 0000000..7261eec
Binary files /dev/null and b/fuzzers/corpora/commit_graph/88b7de1bd1c96454a1350286d115c0ee368511f9 differ
diff --git a/fuzzers/corpora/commit_graph/896268e4a5775b7ce33923ac6daeb0810420c55b b/fuzzers/corpora/commit_graph/896268e4a5775b7ce33923ac6daeb0810420c55b
new file mode 100644 (file)
index 0000000..0897bda
Binary files /dev/null and b/fuzzers/corpora/commit_graph/896268e4a5775b7ce33923ac6daeb0810420c55b differ
diff --git a/fuzzers/corpora/commit_graph/8978f8da89f9652878edabad164f5513ef508f27 b/fuzzers/corpora/commit_graph/8978f8da89f9652878edabad164f5513ef508f27
new file mode 100644 (file)
index 0000000..0dd9ba4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8978f8da89f9652878edabad164f5513ef508f27 differ
diff --git a/fuzzers/corpora/commit_graph/89a6525b7db0e6ec211a484efd2880abef928d4e b/fuzzers/corpora/commit_graph/89a6525b7db0e6ec211a484efd2880abef928d4e
new file mode 100644 (file)
index 0000000..e5dd1cd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/89a6525b7db0e6ec211a484efd2880abef928d4e differ
diff --git a/fuzzers/corpora/commit_graph/8ae86cba2bba6664fc5eb97be8e9777b8825d823 b/fuzzers/corpora/commit_graph/8ae86cba2bba6664fc5eb97be8e9777b8825d823
new file mode 100644 (file)
index 0000000..04a4aa5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8ae86cba2bba6664fc5eb97be8e9777b8825d823 differ
diff --git a/fuzzers/corpora/commit_graph/8b845fbd2aa14e4f83c4dbc8b4b0b54d06482acd b/fuzzers/corpora/commit_graph/8b845fbd2aa14e4f83c4dbc8b4b0b54d06482acd
new file mode 100644 (file)
index 0000000..c711793
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8b845fbd2aa14e4f83c4dbc8b4b0b54d06482acd differ
diff --git a/fuzzers/corpora/commit_graph/8c4121e6ce5956cfa408b980f16d276f456374dc b/fuzzers/corpora/commit_graph/8c4121e6ce5956cfa408b980f16d276f456374dc
new file mode 100644 (file)
index 0000000..1ba1891
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8c4121e6ce5956cfa408b980f16d276f456374dc differ
diff --git a/fuzzers/corpora/commit_graph/8cb6a5b8ab41e3d27668d5735b5c09ff1f2eab65 b/fuzzers/corpora/commit_graph/8cb6a5b8ab41e3d27668d5735b5c09ff1f2eab65
new file mode 100644 (file)
index 0000000..e23d112
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8cb6a5b8ab41e3d27668d5735b5c09ff1f2eab65 differ
diff --git a/fuzzers/corpora/commit_graph/8d80a70ffd362a89b88663e27f11e8ab69b70c1b b/fuzzers/corpora/commit_graph/8d80a70ffd362a89b88663e27f11e8ab69b70c1b
new file mode 100644 (file)
index 0000000..02f765e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8d80a70ffd362a89b88663e27f11e8ab69b70c1b differ
diff --git a/fuzzers/corpora/commit_graph/8db603c1720b3680047f831f2ea9862567a7cdc4 b/fuzzers/corpora/commit_graph/8db603c1720b3680047f831f2ea9862567a7cdc4
new file mode 100644 (file)
index 0000000..d02cb03
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8db603c1720b3680047f831f2ea9862567a7cdc4 differ
diff --git a/fuzzers/corpora/commit_graph/8dd40b2d27c7dd4b986c35d87f826da287c09c4c b/fuzzers/corpora/commit_graph/8dd40b2d27c7dd4b986c35d87f826da287c09c4c
new file mode 100644 (file)
index 0000000..11aa235
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8dd40b2d27c7dd4b986c35d87f826da287c09c4c differ
diff --git a/fuzzers/corpora/commit_graph/8e9d6e6408e5f708a1924e8370e687e2c202a4c4 b/fuzzers/corpora/commit_graph/8e9d6e6408e5f708a1924e8370e687e2c202a4c4
new file mode 100644 (file)
index 0000000..cbeb46b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8e9d6e6408e5f708a1924e8370e687e2c202a4c4 differ
diff --git a/fuzzers/corpora/commit_graph/8f2dff1a30ee28e5985cb9379828aea5658d5849 b/fuzzers/corpora/commit_graph/8f2dff1a30ee28e5985cb9379828aea5658d5849
new file mode 100644 (file)
index 0000000..b7220c3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8f2dff1a30ee28e5985cb9379828aea5658d5849 differ
diff --git a/fuzzers/corpora/commit_graph/8f7d18cdd6e605b85784ada14571fd5e5a184f2a b/fuzzers/corpora/commit_graph/8f7d18cdd6e605b85784ada14571fd5e5a184f2a
new file mode 100644 (file)
index 0000000..80fe175
Binary files /dev/null and b/fuzzers/corpora/commit_graph/8f7d18cdd6e605b85784ada14571fd5e5a184f2a differ
diff --git a/fuzzers/corpora/commit_graph/903ae52f0ac9af8348038b12f9259741b0de42f1 b/fuzzers/corpora/commit_graph/903ae52f0ac9af8348038b12f9259741b0de42f1
new file mode 100644 (file)
index 0000000..da8c220
Binary files /dev/null and b/fuzzers/corpora/commit_graph/903ae52f0ac9af8348038b12f9259741b0de42f1 differ
diff --git a/fuzzers/corpora/commit_graph/9119e331f59e9337d419739c324f49d1bd62c8bf b/fuzzers/corpora/commit_graph/9119e331f59e9337d419739c324f49d1bd62c8bf
new file mode 100644 (file)
index 0000000..fc3a696
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9119e331f59e9337d419739c324f49d1bd62c8bf differ
diff --git a/fuzzers/corpora/commit_graph/91d54d03b0917314ea1d67a70690df9247dd08d2 b/fuzzers/corpora/commit_graph/91d54d03b0917314ea1d67a70690df9247dd08d2
new file mode 100644 (file)
index 0000000..290da4d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/91d54d03b0917314ea1d67a70690df9247dd08d2 differ
diff --git a/fuzzers/corpora/commit_graph/922da3b96725bfd0e3f6ce119f1e2249d53f9086 b/fuzzers/corpora/commit_graph/922da3b96725bfd0e3f6ce119f1e2249d53f9086
new file mode 100644 (file)
index 0000000..c3bb009
Binary files /dev/null and b/fuzzers/corpora/commit_graph/922da3b96725bfd0e3f6ce119f1e2249d53f9086 differ
diff --git a/fuzzers/corpora/commit_graph/9277561e0524cccba2f851970b0d88ec4f4d3f5e b/fuzzers/corpora/commit_graph/9277561e0524cccba2f851970b0d88ec4f4d3f5e
new file mode 100644 (file)
index 0000000..07d1da1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9277561e0524cccba2f851970b0d88ec4f4d3f5e differ
diff --git a/fuzzers/corpora/commit_graph/92a4d571804026b7bbe957396185e079e756b894 b/fuzzers/corpora/commit_graph/92a4d571804026b7bbe957396185e079e756b894
new file mode 100644 (file)
index 0000000..63b98b3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/92a4d571804026b7bbe957396185e079e756b894 differ
diff --git a/fuzzers/corpora/commit_graph/931224cc80168fd362a360d99bab813ed7bbf8ce b/fuzzers/corpora/commit_graph/931224cc80168fd362a360d99bab813ed7bbf8ce
new file mode 100644 (file)
index 0000000..df27b36
Binary files /dev/null and b/fuzzers/corpora/commit_graph/931224cc80168fd362a360d99bab813ed7bbf8ce differ
diff --git a/fuzzers/corpora/commit_graph/936ea5dad3bf023c552aa0bbeea8f7f66a11612c b/fuzzers/corpora/commit_graph/936ea5dad3bf023c552aa0bbeea8f7f66a11612c
new file mode 100644 (file)
index 0000000..847b537
Binary files /dev/null and b/fuzzers/corpora/commit_graph/936ea5dad3bf023c552aa0bbeea8f7f66a11612c differ
diff --git a/fuzzers/corpora/commit_graph/93aa4e0b1864933dce0abc0df69fe3d261f117f2 b/fuzzers/corpora/commit_graph/93aa4e0b1864933dce0abc0df69fe3d261f117f2
new file mode 100644 (file)
index 0000000..ac830ca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/93aa4e0b1864933dce0abc0df69fe3d261f117f2 differ
diff --git a/fuzzers/corpora/commit_graph/93d5b084965cf1b09085c4079a972e25207b3659 b/fuzzers/corpora/commit_graph/93d5b084965cf1b09085c4079a972e25207b3659
new file mode 100644 (file)
index 0000000..02a711a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/93d5b084965cf1b09085c4079a972e25207b3659 differ
diff --git a/fuzzers/corpora/commit_graph/9443fd3468bcc0bc3ff8dfe765225f045ab43d0a b/fuzzers/corpora/commit_graph/9443fd3468bcc0bc3ff8dfe765225f045ab43d0a
new file mode 100644 (file)
index 0000000..d1667ca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9443fd3468bcc0bc3ff8dfe765225f045ab43d0a differ
diff --git a/fuzzers/corpora/commit_graph/9624c26cefb5804b7906147d262e81ee4000b6d6 b/fuzzers/corpora/commit_graph/9624c26cefb5804b7906147d262e81ee4000b6d6
new file mode 100644 (file)
index 0000000..4c18831
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9624c26cefb5804b7906147d262e81ee4000b6d6 differ
diff --git a/fuzzers/corpora/commit_graph/9890933a73f39208627bd36e2fe88a6d54343a74 b/fuzzers/corpora/commit_graph/9890933a73f39208627bd36e2fe88a6d54343a74
new file mode 100644 (file)
index 0000000..dfbb39d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9890933a73f39208627bd36e2fe88a6d54343a74 differ
diff --git a/fuzzers/corpora/commit_graph/989dad0448e79af10040d5080f74eba2b8a401ba b/fuzzers/corpora/commit_graph/989dad0448e79af10040d5080f74eba2b8a401ba
new file mode 100644 (file)
index 0000000..202bbd6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/989dad0448e79af10040d5080f74eba2b8a401ba differ
diff --git a/fuzzers/corpora/commit_graph/98ed4808b4a8da66a91fcea1be63be6371a7c7ac b/fuzzers/corpora/commit_graph/98ed4808b4a8da66a91fcea1be63be6371a7c7ac
new file mode 100644 (file)
index 0000000..b06a167
Binary files /dev/null and b/fuzzers/corpora/commit_graph/98ed4808b4a8da66a91fcea1be63be6371a7c7ac differ
diff --git a/fuzzers/corpora/commit_graph/9928e516b85e22fbad58d562d3b7e814d9ce812d b/fuzzers/corpora/commit_graph/9928e516b85e22fbad58d562d3b7e814d9ce812d
new file mode 100644 (file)
index 0000000..d1e5a04
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9928e516b85e22fbad58d562d3b7e814d9ce812d differ
diff --git a/fuzzers/corpora/commit_graph/994c7cc5599252b5628d89cd0ba4b5574d32bf00 b/fuzzers/corpora/commit_graph/994c7cc5599252b5628d89cd0ba4b5574d32bf00
new file mode 100644 (file)
index 0000000..d51d00d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/994c7cc5599252b5628d89cd0ba4b5574d32bf00 differ
diff --git a/fuzzers/corpora/commit_graph/99c8557c2a02ea030de42869af42c1f7c77114db b/fuzzers/corpora/commit_graph/99c8557c2a02ea030de42869af42c1f7c77114db
new file mode 100644 (file)
index 0000000..18f5349
Binary files /dev/null and b/fuzzers/corpora/commit_graph/99c8557c2a02ea030de42869af42c1f7c77114db differ
diff --git a/fuzzers/corpora/commit_graph/9a14c867272f102b84efdba73662d318c3e51cfe b/fuzzers/corpora/commit_graph/9a14c867272f102b84efdba73662d318c3e51cfe
new file mode 100644 (file)
index 0000000..fc473b2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9a14c867272f102b84efdba73662d318c3e51cfe differ
diff --git a/fuzzers/corpora/commit_graph/9a6f158c176d4a1982d541be2bc27a8afba4ea57 b/fuzzers/corpora/commit_graph/9a6f158c176d4a1982d541be2bc27a8afba4ea57
new file mode 100644 (file)
index 0000000..b99bc20
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9a6f158c176d4a1982d541be2bc27a8afba4ea57 differ
diff --git a/fuzzers/corpora/commit_graph/9aa4af603192823a2fdc53d95ed36896bc3309b2 b/fuzzers/corpora/commit_graph/9aa4af603192823a2fdc53d95ed36896bc3309b2
new file mode 100644 (file)
index 0000000..c36e298
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9aa4af603192823a2fdc53d95ed36896bc3309b2 differ
diff --git a/fuzzers/corpora/commit_graph/9b40c2190123cec66af3b37212f6c567869efda3 b/fuzzers/corpora/commit_graph/9b40c2190123cec66af3b37212f6c567869efda3
new file mode 100644 (file)
index 0000000..1662324
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9b40c2190123cec66af3b37212f6c567869efda3 differ
diff --git a/fuzzers/corpora/commit_graph/9b6268c11d78c35db5164f1346905e602b6a49fe b/fuzzers/corpora/commit_graph/9b6268c11d78c35db5164f1346905e602b6a49fe
new file mode 100644 (file)
index 0000000..4106e20
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9b6268c11d78c35db5164f1346905e602b6a49fe differ
diff --git a/fuzzers/corpora/commit_graph/9c6883ba5cedb7d711b12733d66ef1a1156dd0af b/fuzzers/corpora/commit_graph/9c6883ba5cedb7d711b12733d66ef1a1156dd0af
new file mode 100644 (file)
index 0000000..84a193c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9c6883ba5cedb7d711b12733d66ef1a1156dd0af differ
diff --git a/fuzzers/corpora/commit_graph/9c85c90f44b454ce0d52882c447f5ecb8d303634 b/fuzzers/corpora/commit_graph/9c85c90f44b454ce0d52882c447f5ecb8d303634
new file mode 100644 (file)
index 0000000..e17438b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9c85c90f44b454ce0d52882c447f5ecb8d303634 differ
diff --git a/fuzzers/corpora/commit_graph/9cb7a2e89ec636da3fd41ecc49ebe25e5344e2c6 b/fuzzers/corpora/commit_graph/9cb7a2e89ec636da3fd41ecc49ebe25e5344e2c6
new file mode 100644 (file)
index 0000000..55f76fd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9cb7a2e89ec636da3fd41ecc49ebe25e5344e2c6 differ
diff --git a/fuzzers/corpora/commit_graph/9d912dc5a3497e4b5b40b37202fc0ffbf5263666 b/fuzzers/corpora/commit_graph/9d912dc5a3497e4b5b40b37202fc0ffbf5263666
new file mode 100644 (file)
index 0000000..c71c31a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9d912dc5a3497e4b5b40b37202fc0ffbf5263666 differ
diff --git a/fuzzers/corpora/commit_graph/9dcbafe8c5345194ee0ce7eb4f6efaeb55543626 b/fuzzers/corpora/commit_graph/9dcbafe8c5345194ee0ce7eb4f6efaeb55543626
new file mode 100644 (file)
index 0000000..42c5e7d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9dcbafe8c5345194ee0ce7eb4f6efaeb55543626 differ
diff --git a/fuzzers/corpora/commit_graph/9f4b0f3d2d25e6405ba6093f24d0605327711573 b/fuzzers/corpora/commit_graph/9f4b0f3d2d25e6405ba6093f24d0605327711573
new file mode 100644 (file)
index 0000000..0dc94be
Binary files /dev/null and b/fuzzers/corpora/commit_graph/9f4b0f3d2d25e6405ba6093f24d0605327711573 differ
diff --git a/fuzzers/corpora/commit_graph/a047bf683239fa208dbac09424b105820ac23f43 b/fuzzers/corpora/commit_graph/a047bf683239fa208dbac09424b105820ac23f43
new file mode 100644 (file)
index 0000000..925c86c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a047bf683239fa208dbac09424b105820ac23f43 differ
diff --git a/fuzzers/corpora/commit_graph/a1379dcd89ef5e73eabbfcc395113e3636e0ae09 b/fuzzers/corpora/commit_graph/a1379dcd89ef5e73eabbfcc395113e3636e0ae09
new file mode 100644 (file)
index 0000000..43d31b6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a1379dcd89ef5e73eabbfcc395113e3636e0ae09 differ
diff --git a/fuzzers/corpora/commit_graph/a38c7ef56adabd0916abac514154b1f362d40434 b/fuzzers/corpora/commit_graph/a38c7ef56adabd0916abac514154b1f362d40434
new file mode 100644 (file)
index 0000000..944b4ea
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a38c7ef56adabd0916abac514154b1f362d40434 differ
diff --git a/fuzzers/corpora/commit_graph/a38ec6ad4a8466b4feb88e67b16524e8f3feac64 b/fuzzers/corpora/commit_graph/a38ec6ad4a8466b4feb88e67b16524e8f3feac64
new file mode 100644 (file)
index 0000000..a9d1adb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a38ec6ad4a8466b4feb88e67b16524e8f3feac64 differ
diff --git a/fuzzers/corpora/commit_graph/a3fdea21020268b3b2409c1115d50697d9ae8f8c b/fuzzers/corpora/commit_graph/a3fdea21020268b3b2409c1115d50697d9ae8f8c
new file mode 100644 (file)
index 0000000..8d4f934
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a3fdea21020268b3b2409c1115d50697d9ae8f8c differ
diff --git a/fuzzers/corpora/commit_graph/a45f1987a444b2c27e90fc1477e8b0815f75383f b/fuzzers/corpora/commit_graph/a45f1987a444b2c27e90fc1477e8b0815f75383f
new file mode 100644 (file)
index 0000000..d211a8b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a45f1987a444b2c27e90fc1477e8b0815f75383f differ
diff --git a/fuzzers/corpora/commit_graph/a4682958fb7029384c0a01a4a1356ac6f2f44fe1 b/fuzzers/corpora/commit_graph/a4682958fb7029384c0a01a4a1356ac6f2f44fe1
new file mode 100644 (file)
index 0000000..e8f66dc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a4682958fb7029384c0a01a4a1356ac6f2f44fe1 differ
diff --git a/fuzzers/corpora/commit_graph/a4de41561725960d6f48f210a4fb74d527f7b0c2 b/fuzzers/corpora/commit_graph/a4de41561725960d6f48f210a4fb74d527f7b0c2
new file mode 100644 (file)
index 0000000..ac4c41c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a4de41561725960d6f48f210a4fb74d527f7b0c2 differ
diff --git a/fuzzers/corpora/commit_graph/a5935f34435ecdd6587ad4f77b20d479d3387dbe b/fuzzers/corpora/commit_graph/a5935f34435ecdd6587ad4f77b20d479d3387dbe
new file mode 100644 (file)
index 0000000..2e00f59
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a5935f34435ecdd6587ad4f77b20d479d3387dbe differ
diff --git a/fuzzers/corpora/commit_graph/a5b394beb2b1d463ad80924a8c8c70584bf5c629 b/fuzzers/corpora/commit_graph/a5b394beb2b1d463ad80924a8c8c70584bf5c629
new file mode 100644 (file)
index 0000000..eb8f700
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a5b394beb2b1d463ad80924a8c8c70584bf5c629 differ
diff --git a/fuzzers/corpora/commit_graph/a62bc806f8c98ba7986243c2185a0548a8dd57ef b/fuzzers/corpora/commit_graph/a62bc806f8c98ba7986243c2185a0548a8dd57ef
new file mode 100644 (file)
index 0000000..fb30d9e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a62bc806f8c98ba7986243c2185a0548a8dd57ef differ
diff --git a/fuzzers/corpora/commit_graph/a7013e97948893e0118c686c06e332cc611bea7e b/fuzzers/corpora/commit_graph/a7013e97948893e0118c686c06e332cc611bea7e
new file mode 100644 (file)
index 0000000..ab50113
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a7013e97948893e0118c686c06e332cc611bea7e differ
diff --git a/fuzzers/corpora/commit_graph/a74f5df8c7f25c37c15c0f74ed50019d17338225 b/fuzzers/corpora/commit_graph/a74f5df8c7f25c37c15c0f74ed50019d17338225
new file mode 100644 (file)
index 0000000..b234c15
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a74f5df8c7f25c37c15c0f74ed50019d17338225 differ
diff --git a/fuzzers/corpora/commit_graph/a7ab3559fb3da3f027e67091116253f3bdfd7828 b/fuzzers/corpora/commit_graph/a7ab3559fb3da3f027e67091116253f3bdfd7828
new file mode 100644 (file)
index 0000000..838337a
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a7ab3559fb3da3f027e67091116253f3bdfd7828 differ
diff --git a/fuzzers/corpora/commit_graph/a845c8258a02022d447ea9249788b345f5504648 b/fuzzers/corpora/commit_graph/a845c8258a02022d447ea9249788b345f5504648
new file mode 100644 (file)
index 0000000..78311d9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a845c8258a02022d447ea9249788b345f5504648 differ
diff --git a/fuzzers/corpora/commit_graph/a8d3e026e2393587eb170afb32e94ff0e1f8a8be b/fuzzers/corpora/commit_graph/a8d3e026e2393587eb170afb32e94ff0e1f8a8be
new file mode 100644 (file)
index 0000000..54457f3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a8d3e026e2393587eb170afb32e94ff0e1f8a8be differ
diff --git a/fuzzers/corpora/commit_graph/a8d547e41ee21e163e65cf0a186d469dfa50ec19 b/fuzzers/corpora/commit_graph/a8d547e41ee21e163e65cf0a186d469dfa50ec19
new file mode 100644 (file)
index 0000000..52d265b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a8d547e41ee21e163e65cf0a186d469dfa50ec19 differ
diff --git a/fuzzers/corpora/commit_graph/a8fa22521dd6813e595cc0a9586ee71fff305fe2 b/fuzzers/corpora/commit_graph/a8fa22521dd6813e595cc0a9586ee71fff305fe2
new file mode 100644 (file)
index 0000000..5f90995
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a8fa22521dd6813e595cc0a9586ee71fff305fe2 differ
diff --git a/fuzzers/corpora/commit_graph/a9969442d585d9a53259c71c73b095701280eac5 b/fuzzers/corpora/commit_graph/a9969442d585d9a53259c71c73b095701280eac5
new file mode 100644 (file)
index 0000000..f757928
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a9969442d585d9a53259c71c73b095701280eac5 differ
diff --git a/fuzzers/corpora/commit_graph/a99789d0ce2d7b937aaa8afa3cfc0f4ccd7be95f b/fuzzers/corpora/commit_graph/a99789d0ce2d7b937aaa8afa3cfc0f4ccd7be95f
new file mode 100644 (file)
index 0000000..471add5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/a99789d0ce2d7b937aaa8afa3cfc0f4ccd7be95f differ
diff --git a/fuzzers/corpora/commit_graph/aaca30ee3ab38edfa2b061fcbcbca0c0ea657f15 b/fuzzers/corpora/commit_graph/aaca30ee3ab38edfa2b061fcbcbca0c0ea657f15
new file mode 100644 (file)
index 0000000..cc981c1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/aaca30ee3ab38edfa2b061fcbcbca0c0ea657f15 differ
diff --git a/fuzzers/corpora/commit_graph/aacdec3f05e98eb6eedddb9c6edb968e1a63c551 b/fuzzers/corpora/commit_graph/aacdec3f05e98eb6eedddb9c6edb968e1a63c551
new file mode 100644 (file)
index 0000000..622c247
Binary files /dev/null and b/fuzzers/corpora/commit_graph/aacdec3f05e98eb6eedddb9c6edb968e1a63c551 differ
diff --git a/fuzzers/corpora/commit_graph/aadd85127241b94a41d02d9e9699e3e9773de1c9 b/fuzzers/corpora/commit_graph/aadd85127241b94a41d02d9e9699e3e9773de1c9
new file mode 100644 (file)
index 0000000..b84e5f1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/aadd85127241b94a41d02d9e9699e3e9773de1c9 differ
diff --git a/fuzzers/corpora/commit_graph/ab8ad126702803d21dbafc85713bbee7f25f36e5 b/fuzzers/corpora/commit_graph/ab8ad126702803d21dbafc85713bbee7f25f36e5
new file mode 100644 (file)
index 0000000..9a19eda
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ab8ad126702803d21dbafc85713bbee7f25f36e5 differ
diff --git a/fuzzers/corpora/commit_graph/ac26f9afd599ff6f33396c2e02130654f3e2390c b/fuzzers/corpora/commit_graph/ac26f9afd599ff6f33396c2e02130654f3e2390c
new file mode 100644 (file)
index 0000000..843eaa2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ac26f9afd599ff6f33396c2e02130654f3e2390c differ
diff --git a/fuzzers/corpora/commit_graph/ac8b129e4756fda0c50c9dd0eb13e34c7b41ce8e b/fuzzers/corpora/commit_graph/ac8b129e4756fda0c50c9dd0eb13e34c7b41ce8e
new file mode 100644 (file)
index 0000000..4b41d07
--- /dev/null
@@ -0,0 +1 @@
+ïïï\9cïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï@ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïë
\ No newline at end of file
diff --git a/fuzzers/corpora/commit_graph/aceaf3b72c2627dd3dd065974b854150681c093f b/fuzzers/corpora/commit_graph/aceaf3b72c2627dd3dd065974b854150681c093f
new file mode 100644 (file)
index 0000000..d490782
Binary files /dev/null and b/fuzzers/corpora/commit_graph/aceaf3b72c2627dd3dd065974b854150681c093f differ
diff --git a/fuzzers/corpora/commit_graph/ad1fcdc3bf806392e754a902eba9edd3b344c31f b/fuzzers/corpora/commit_graph/ad1fcdc3bf806392e754a902eba9edd3b344c31f
new file mode 100644 (file)
index 0000000..1379b75
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ad1fcdc3bf806392e754a902eba9edd3b344c31f differ
diff --git a/fuzzers/corpora/commit_graph/ad8c80e532482f9dfbfbb7c0d447f1f4e592bf72 b/fuzzers/corpora/commit_graph/ad8c80e532482f9dfbfbb7c0d447f1f4e592bf72
new file mode 100644 (file)
index 0000000..bfe3911
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ad8c80e532482f9dfbfbb7c0d447f1f4e592bf72 differ
diff --git a/fuzzers/corpora/commit_graph/add92b71bf897da2f71f691e6abcb6d02cb8e99f b/fuzzers/corpora/commit_graph/add92b71bf897da2f71f691e6abcb6d02cb8e99f
new file mode 100644 (file)
index 0000000..1676dbf
Binary files /dev/null and b/fuzzers/corpora/commit_graph/add92b71bf897da2f71f691e6abcb6d02cb8e99f differ
diff --git a/fuzzers/corpora/commit_graph/aeb8ccf6d82be9236c9e689e1580d043bd701eb0 b/fuzzers/corpora/commit_graph/aeb8ccf6d82be9236c9e689e1580d043bd701eb0
new file mode 100644 (file)
index 0000000..10688e3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/aeb8ccf6d82be9236c9e689e1580d043bd701eb0 differ
diff --git a/fuzzers/corpora/commit_graph/af1a827aedbf674fff2bdeb5589554eec62787ab b/fuzzers/corpora/commit_graph/af1a827aedbf674fff2bdeb5589554eec62787ab
new file mode 100644 (file)
index 0000000..6f08ae5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/af1a827aedbf674fff2bdeb5589554eec62787ab differ
diff --git a/fuzzers/corpora/commit_graph/afaab9a75414d231176ad4582b6f8d81b5dbedb3 b/fuzzers/corpora/commit_graph/afaab9a75414d231176ad4582b6f8d81b5dbedb3
new file mode 100644 (file)
index 0000000..8701780
Binary files /dev/null and b/fuzzers/corpora/commit_graph/afaab9a75414d231176ad4582b6f8d81b5dbedb3 differ
diff --git a/fuzzers/corpora/commit_graph/afc12c4ebed1f3ab962d7dcef110b5328b1e24c3 b/fuzzers/corpora/commit_graph/afc12c4ebed1f3ab962d7dcef110b5328b1e24c3
new file mode 100644 (file)
index 0000000..0e10f77
Binary files /dev/null and b/fuzzers/corpora/commit_graph/afc12c4ebed1f3ab962d7dcef110b5328b1e24c3 differ
diff --git a/fuzzers/corpora/commit_graph/b0044f3744cf019658d668a33f8d1e53ef8bd6ce b/fuzzers/corpora/commit_graph/b0044f3744cf019658d668a33f8d1e53ef8bd6ce
new file mode 100644 (file)
index 0000000..ede7bfe
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b0044f3744cf019658d668a33f8d1e53ef8bd6ce differ
diff --git a/fuzzers/corpora/commit_graph/b06adc81a4e1cdcda3786970ca07ed9dee0b6401 b/fuzzers/corpora/commit_graph/b06adc81a4e1cdcda3786970ca07ed9dee0b6401
new file mode 100644 (file)
index 0000000..b5f08b2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b06adc81a4e1cdcda3786970ca07ed9dee0b6401 differ
diff --git a/fuzzers/corpora/commit_graph/b139802a1cc90fd5b86cae044c221361892c688d b/fuzzers/corpora/commit_graph/b139802a1cc90fd5b86cae044c221361892c688d
new file mode 100644 (file)
index 0000000..c21f39e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b139802a1cc90fd5b86cae044c221361892c688d differ
diff --git a/fuzzers/corpora/commit_graph/b1b8f251542db01bdb01be3b6d5b117b07db1834 b/fuzzers/corpora/commit_graph/b1b8f251542db01bdb01be3b6d5b117b07db1834
new file mode 100644 (file)
index 0000000..b42f726
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b1b8f251542db01bdb01be3b6d5b117b07db1834 differ
diff --git a/fuzzers/corpora/commit_graph/b1b9af93f84ed6861b9c0ade39980e89ef828c8f b/fuzzers/corpora/commit_graph/b1b9af93f84ed6861b9c0ade39980e89ef828c8f
new file mode 100644 (file)
index 0000000..b367b87
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b1b9af93f84ed6861b9c0ade39980e89ef828c8f differ
diff --git a/fuzzers/corpora/commit_graph/b2eae68035cafd4077f6a4c3e4e961fdc1e8122b b/fuzzers/corpora/commit_graph/b2eae68035cafd4077f6a4c3e4e961fdc1e8122b
new file mode 100644 (file)
index 0000000..1c62898
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b2eae68035cafd4077f6a4c3e4e961fdc1e8122b differ
diff --git a/fuzzers/corpora/commit_graph/b32897a6aedaa8c5a6e656dd808bafabc4ee5608 b/fuzzers/corpora/commit_graph/b32897a6aedaa8c5a6e656dd808bafabc4ee5608
new file mode 100644 (file)
index 0000000..b3fbb81
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b32897a6aedaa8c5a6e656dd808bafabc4ee5608 differ
diff --git a/fuzzers/corpora/commit_graph/b376e4fc517297f92ac1713803ae3b60d5ebbe43 b/fuzzers/corpora/commit_graph/b376e4fc517297f92ac1713803ae3b60d5ebbe43
new file mode 100644 (file)
index 0000000..637eafd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b376e4fc517297f92ac1713803ae3b60d5ebbe43 differ
diff --git a/fuzzers/corpora/commit_graph/b3fd100b139cfbffaad68aacf7d462861e9dca35 b/fuzzers/corpora/commit_graph/b3fd100b139cfbffaad68aacf7d462861e9dca35
new file mode 100644 (file)
index 0000000..da105f5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b3fd100b139cfbffaad68aacf7d462861e9dca35 differ
diff --git a/fuzzers/corpora/commit_graph/b40808ca955faab4829811bced1cccb2ab58ea58 b/fuzzers/corpora/commit_graph/b40808ca955faab4829811bced1cccb2ab58ea58
new file mode 100644 (file)
index 0000000..4daa741
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b40808ca955faab4829811bced1cccb2ab58ea58 differ
diff --git a/fuzzers/corpora/commit_graph/b43daf9f87a514bce74af3e5a39284c69c4e7011 b/fuzzers/corpora/commit_graph/b43daf9f87a514bce74af3e5a39284c69c4e7011
new file mode 100644 (file)
index 0000000..5c8129d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b43daf9f87a514bce74af3e5a39284c69c4e7011 differ
diff --git a/fuzzers/corpora/commit_graph/b477da07f3e5796ff4a98c8a5bdb0e4a634954bf b/fuzzers/corpora/commit_graph/b477da07f3e5796ff4a98c8a5bdb0e4a634954bf
new file mode 100644 (file)
index 0000000..dbe8abe
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b477da07f3e5796ff4a98c8a5bdb0e4a634954bf differ
diff --git a/fuzzers/corpora/commit_graph/b4a2ef09cf59ca5ccf810a6f001cce710cc02f6b b/fuzzers/corpora/commit_graph/b4a2ef09cf59ca5ccf810a6f001cce710cc02f6b
new file mode 100644 (file)
index 0000000..3a58173
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b4a2ef09cf59ca5ccf810a6f001cce710cc02f6b differ
diff --git a/fuzzers/corpora/commit_graph/b4b75e588cb83430c502a34ec3dcfaf774a00359 b/fuzzers/corpora/commit_graph/b4b75e588cb83430c502a34ec3dcfaf774a00359
new file mode 100644 (file)
index 0000000..4afd452
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b4b75e588cb83430c502a34ec3dcfaf774a00359 differ
diff --git a/fuzzers/corpora/commit_graph/b4ce98acd2b288b6cfc00461e2e15e0f8004030c b/fuzzers/corpora/commit_graph/b4ce98acd2b288b6cfc00461e2e15e0f8004030c
new file mode 100644 (file)
index 0000000..a707426
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b4ce98acd2b288b6cfc00461e2e15e0f8004030c differ
diff --git a/fuzzers/corpora/commit_graph/b75563f30f7e4fb369d2449b723ee8b282d03eff b/fuzzers/corpora/commit_graph/b75563f30f7e4fb369d2449b723ee8b282d03eff
new file mode 100644 (file)
index 0000000..a101bca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b75563f30f7e4fb369d2449b723ee8b282d03eff differ
diff --git a/fuzzers/corpora/commit_graph/b7a0a820afa7057081de186728d0d887131d9314 b/fuzzers/corpora/commit_graph/b7a0a820afa7057081de186728d0d887131d9314
new file mode 100644 (file)
index 0000000..915cc26
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b7a0a820afa7057081de186728d0d887131d9314 differ
diff --git a/fuzzers/corpora/commit_graph/b7e880446146c735a3f820fb93969c8c172c2fb5 b/fuzzers/corpora/commit_graph/b7e880446146c735a3f820fb93969c8c172c2fb5
new file mode 100644 (file)
index 0000000..cd26631
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b7e880446146c735a3f820fb93969c8c172c2fb5 differ
diff --git a/fuzzers/corpora/commit_graph/b833073d3006e7cbac03c494603a9b75e7b2a723 b/fuzzers/corpora/commit_graph/b833073d3006e7cbac03c494603a9b75e7b2a723
new file mode 100644 (file)
index 0000000..0798037
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b833073d3006e7cbac03c494603a9b75e7b2a723 differ
diff --git a/fuzzers/corpora/commit_graph/b89459c1fb6fc918db4c81a32a75ee66217f9ab8 b/fuzzers/corpora/commit_graph/b89459c1fb6fc918db4c81a32a75ee66217f9ab8
new file mode 100644 (file)
index 0000000..bdc6de6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b89459c1fb6fc918db4c81a32a75ee66217f9ab8 differ
diff --git a/fuzzers/corpora/commit_graph/b8aab6c9b2c706f8df0ff695ff94969171f9c807 b/fuzzers/corpora/commit_graph/b8aab6c9b2c706f8df0ff695ff94969171f9c807
new file mode 100644 (file)
index 0000000..810a305
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b8aab6c9b2c706f8df0ff695ff94969171f9c807 differ
diff --git a/fuzzers/corpora/commit_graph/b9751182a36acb79b77585e1e379857a530e95c8 b/fuzzers/corpora/commit_graph/b9751182a36acb79b77585e1e379857a530e95c8
new file mode 100644 (file)
index 0000000..eeb1ed0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b9751182a36acb79b77585e1e379857a530e95c8 differ
diff --git a/fuzzers/corpora/commit_graph/b9ddb239b5a2c1348d972ec70a08507c35ba4432 b/fuzzers/corpora/commit_graph/b9ddb239b5a2c1348d972ec70a08507c35ba4432
new file mode 100644 (file)
index 0000000..0d746e5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/b9ddb239b5a2c1348d972ec70a08507c35ba4432 differ
diff --git a/fuzzers/corpora/commit_graph/ba8f573256a0fbb95c5626f399ebc3ef50bbd826 b/fuzzers/corpora/commit_graph/ba8f573256a0fbb95c5626f399ebc3ef50bbd826
new file mode 100644 (file)
index 0000000..330229e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ba8f573256a0fbb95c5626f399ebc3ef50bbd826 differ
diff --git a/fuzzers/corpora/commit_graph/bc165749042d5425c5d6d4e29b17769a2315a80d b/fuzzers/corpora/commit_graph/bc165749042d5425c5d6d4e29b17769a2315a80d
new file mode 100644 (file)
index 0000000..af0d232
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bc165749042d5425c5d6d4e29b17769a2315a80d differ
diff --git a/fuzzers/corpora/commit_graph/bc910bd349319e1ed44d7c7266e3ac99cc29ecc6 b/fuzzers/corpora/commit_graph/bc910bd349319e1ed44d7c7266e3ac99cc29ecc6
new file mode 100644 (file)
index 0000000..a38abe5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bc910bd349319e1ed44d7c7266e3ac99cc29ecc6 differ
diff --git a/fuzzers/corpora/commit_graph/bc97b1d4f57eb7770bc3983e2d57c8c01b21d29e b/fuzzers/corpora/commit_graph/bc97b1d4f57eb7770bc3983e2d57c8c01b21d29e
new file mode 100644 (file)
index 0000000..631754c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bc97b1d4f57eb7770bc3983e2d57c8c01b21d29e differ
diff --git a/fuzzers/corpora/commit_graph/bd06f768e35ded4437cb88e2bc0ddd0bea3fa84c b/fuzzers/corpora/commit_graph/bd06f768e35ded4437cb88e2bc0ddd0bea3fa84c
new file mode 100644 (file)
index 0000000..954e73d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bd06f768e35ded4437cb88e2bc0ddd0bea3fa84c differ
diff --git a/fuzzers/corpora/commit_graph/bd702faff9725a7a1957fd0f85cc52799f37b682 b/fuzzers/corpora/commit_graph/bd702faff9725a7a1957fd0f85cc52799f37b682
new file mode 100644 (file)
index 0000000..928fe58
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bd702faff9725a7a1957fd0f85cc52799f37b682 differ
diff --git a/fuzzers/corpora/commit_graph/bee4464861e1cae3cfdd5fbcb340efbf02e8d8ca b/fuzzers/corpora/commit_graph/bee4464861e1cae3cfdd5fbcb340efbf02e8d8ca
new file mode 100644 (file)
index 0000000..8f636ce
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bee4464861e1cae3cfdd5fbcb340efbf02e8d8ca differ
diff --git a/fuzzers/corpora/commit_graph/bf7ad994b098ec85d62683a16e067635e21a8af5 b/fuzzers/corpora/commit_graph/bf7ad994b098ec85d62683a16e067635e21a8af5
new file mode 100644 (file)
index 0000000..71ca107
Binary files /dev/null and b/fuzzers/corpora/commit_graph/bf7ad994b098ec85d62683a16e067635e21a8af5 differ
diff --git a/fuzzers/corpora/commit_graph/c054fc89ed72101dec861668ff1738ef85b728b9 b/fuzzers/corpora/commit_graph/c054fc89ed72101dec861668ff1738ef85b728b9
new file mode 100644 (file)
index 0000000..988ab6b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c054fc89ed72101dec861668ff1738ef85b728b9 differ
diff --git a/fuzzers/corpora/commit_graph/c06752415ac037fefe5172dc7245cd7c49ca7fca b/fuzzers/corpora/commit_graph/c06752415ac037fefe5172dc7245cd7c49ca7fca
new file mode 100644 (file)
index 0000000..d03fcac
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c06752415ac037fefe5172dc7245cd7c49ca7fca differ
diff --git a/fuzzers/corpora/commit_graph/c0c8b54354d172a0be751e3e9b80be961bb15ddb b/fuzzers/corpora/commit_graph/c0c8b54354d172a0be751e3e9b80be961bb15ddb
new file mode 100644 (file)
index 0000000..233aa4e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c0c8b54354d172a0be751e3e9b80be961bb15ddb differ
diff --git a/fuzzers/corpora/commit_graph/c0e7ca9b5b4d0e72d23d7dc9e9d1f2463a17a20d b/fuzzers/corpora/commit_graph/c0e7ca9b5b4d0e72d23d7dc9e9d1f2463a17a20d
new file mode 100644 (file)
index 0000000..c36f7c1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c0e7ca9b5b4d0e72d23d7dc9e9d1f2463a17a20d differ
diff --git a/fuzzers/corpora/commit_graph/c13576a29c98bee02aa47f646f5f170f9b7d83f9 b/fuzzers/corpora/commit_graph/c13576a29c98bee02aa47f646f5f170f9b7d83f9
new file mode 100644 (file)
index 0000000..95bdcb9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c13576a29c98bee02aa47f646f5f170f9b7d83f9 differ
diff --git a/fuzzers/corpora/commit_graph/c14edf1d34f40b3cc74772c81ebe5d72172cc662 b/fuzzers/corpora/commit_graph/c14edf1d34f40b3cc74772c81ebe5d72172cc662
new file mode 100644 (file)
index 0000000..63b1e39
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c14edf1d34f40b3cc74772c81ebe5d72172cc662 differ
diff --git a/fuzzers/corpora/commit_graph/c2789364cb35d111f08f924d0d7550ea9785c61e b/fuzzers/corpora/commit_graph/c2789364cb35d111f08f924d0d7550ea9785c61e
new file mode 100644 (file)
index 0000000..0044eb5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c2789364cb35d111f08f924d0d7550ea9785c61e differ
diff --git a/fuzzers/corpora/commit_graph/c2d8b07acb13e43a89b6c4afb3ecb9817dd4a8e9 b/fuzzers/corpora/commit_graph/c2d8b07acb13e43a89b6c4afb3ecb9817dd4a8e9
new file mode 100644 (file)
index 0000000..8cf6a91
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c2d8b07acb13e43a89b6c4afb3ecb9817dd4a8e9 differ
diff --git a/fuzzers/corpora/commit_graph/c36ed796c1bf839668db8fc3475a2ffb32ad8ceb b/fuzzers/corpora/commit_graph/c36ed796c1bf839668db8fc3475a2ffb32ad8ceb
new file mode 100644 (file)
index 0000000..77dd76b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c36ed796c1bf839668db8fc3475a2ffb32ad8ceb differ
diff --git a/fuzzers/corpora/commit_graph/c41ec9dd94427423e4704721e7f21eae0c44ef20 b/fuzzers/corpora/commit_graph/c41ec9dd94427423e4704721e7f21eae0c44ef20
new file mode 100644 (file)
index 0000000..9b828b8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c41ec9dd94427423e4704721e7f21eae0c44ef20 differ
diff --git a/fuzzers/corpora/commit_graph/c42c544fa9dbb1264b39bf920b40985384db1d16 b/fuzzers/corpora/commit_graph/c42c544fa9dbb1264b39bf920b40985384db1d16
new file mode 100644 (file)
index 0000000..6088980
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c42c544fa9dbb1264b39bf920b40985384db1d16 differ
diff --git a/fuzzers/corpora/commit_graph/c45ec3f594abc15de0a8cc3ad748ba23cb34ec64 b/fuzzers/corpora/commit_graph/c45ec3f594abc15de0a8cc3ad748ba23cb34ec64
new file mode 100644 (file)
index 0000000..6a711ba
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c45ec3f594abc15de0a8cc3ad748ba23cb34ec64 differ
diff --git a/fuzzers/corpora/commit_graph/c49004d980961f288616a4eb9ebf68123fd68ffa b/fuzzers/corpora/commit_graph/c49004d980961f288616a4eb9ebf68123fd68ffa
new file mode 100644 (file)
index 0000000..0b5a6bc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c49004d980961f288616a4eb9ebf68123fd68ffa differ
diff --git a/fuzzers/corpora/commit_graph/c4c3c3c8df24adf505127627b3090116de78d9a6 b/fuzzers/corpora/commit_graph/c4c3c3c8df24adf505127627b3090116de78d9a6
new file mode 100644 (file)
index 0000000..528725c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c4c3c3c8df24adf505127627b3090116de78d9a6 differ
diff --git a/fuzzers/corpora/commit_graph/c5c1921293af4a5953cb386092694042715fcfb3 b/fuzzers/corpora/commit_graph/c5c1921293af4a5953cb386092694042715fcfb3
new file mode 100644 (file)
index 0000000..2256d19
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c5c1921293af4a5953cb386092694042715fcfb3 differ
diff --git a/fuzzers/corpora/commit_graph/c615caad21cd8a754fcb2008420234c5511c62b7 b/fuzzers/corpora/commit_graph/c615caad21cd8a754fcb2008420234c5511c62b7
new file mode 100644 (file)
index 0000000..fa4c9cc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c615caad21cd8a754fcb2008420234c5511c62b7 differ
diff --git a/fuzzers/corpora/commit_graph/c6a9ee3f8fdc42566c4799db3912a83c8c438d7f b/fuzzers/corpora/commit_graph/c6a9ee3f8fdc42566c4799db3912a83c8c438d7f
new file mode 100644 (file)
index 0000000..c3c69fc
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c6a9ee3f8fdc42566c4799db3912a83c8c438d7f differ
diff --git a/fuzzers/corpora/commit_graph/c6b661e976282051285b913b3728383f36103ef8 b/fuzzers/corpora/commit_graph/c6b661e976282051285b913b3728383f36103ef8
new file mode 100644 (file)
index 0000000..6a156d2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c6b661e976282051285b913b3728383f36103ef8 differ
diff --git a/fuzzers/corpora/commit_graph/c716ba47f810c238fe7bda1fbdc7b1ccc34e9848 b/fuzzers/corpora/commit_graph/c716ba47f810c238fe7bda1fbdc7b1ccc34e9848
new file mode 100644 (file)
index 0000000..271ec76
--- /dev/null
@@ -0,0 +1 @@
+ïïï\9cïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï@ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï
\ No newline at end of file
diff --git a/fuzzers/corpora/commit_graph/c85b2fa4421302e2fa333a9e33d59a882aa04f4f b/fuzzers/corpora/commit_graph/c85b2fa4421302e2fa333a9e33d59a882aa04f4f
new file mode 100644 (file)
index 0000000..eba46a6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c85b2fa4421302e2fa333a9e33d59a882aa04f4f differ
diff --git a/fuzzers/corpora/commit_graph/c871d135f2d3117b326688355bc0fa6f26d56cd6 b/fuzzers/corpora/commit_graph/c871d135f2d3117b326688355bc0fa6f26d56cd6
new file mode 100644 (file)
index 0000000..6ead612
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c871d135f2d3117b326688355bc0fa6f26d56cd6 differ
diff --git a/fuzzers/corpora/commit_graph/c915b02265a27d185a8b028305f082ddb3ebd704 b/fuzzers/corpora/commit_graph/c915b02265a27d185a8b028305f082ddb3ebd704
new file mode 100644 (file)
index 0000000..1960dfb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c915b02265a27d185a8b028305f082ddb3ebd704 differ
diff --git a/fuzzers/corpora/commit_graph/c952d38b3e642db4795d7f954b85f4f6d2a041aa b/fuzzers/corpora/commit_graph/c952d38b3e642db4795d7f954b85f4f6d2a041aa
new file mode 100644 (file)
index 0000000..b8ee305
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c952d38b3e642db4795d7f954b85f4f6d2a041aa differ
diff --git a/fuzzers/corpora/commit_graph/c98ee52065736c4172f6ee0c31977bf1b560d685 b/fuzzers/corpora/commit_graph/c98ee52065736c4172f6ee0c31977bf1b560d685
new file mode 100644 (file)
index 0000000..f8d7a23
Binary files /dev/null and b/fuzzers/corpora/commit_graph/c98ee52065736c4172f6ee0c31977bf1b560d685 differ
diff --git a/fuzzers/corpora/commit_graph/c99b183a2cd0dd8a4c1a141cc6eebb0311501fa5 b/fuzzers/corpora/commit_graph/c99b183a2cd0dd8a4c1a141cc6eebb0311501fa5
new file mode 100644 (file)
index 0000000..9cd1ad4
--- /dev/null
@@ -0,0 +1 @@
+Ëó@ÿ~
\ No newline at end of file
diff --git a/fuzzers/corpora/commit_graph/ca0cd26baff2f2c0759e619800ebbe7314d2bb95 b/fuzzers/corpora/commit_graph/ca0cd26baff2f2c0759e619800ebbe7314d2bb95
new file mode 100644 (file)
index 0000000..78a357b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ca0cd26baff2f2c0759e619800ebbe7314d2bb95 differ
diff --git a/fuzzers/corpora/commit_graph/ca3e0d745c35d7cceb0f6e3f8a709eb658b7e5a8 b/fuzzers/corpora/commit_graph/ca3e0d745c35d7cceb0f6e3f8a709eb658b7e5a8
new file mode 100644 (file)
index 0000000..174863d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ca3e0d745c35d7cceb0f6e3f8a709eb658b7e5a8 differ
diff --git a/fuzzers/corpora/commit_graph/cac667320e99e93a796bb89842de4675735eb4a4 b/fuzzers/corpora/commit_graph/cac667320e99e93a796bb89842de4675735eb4a4
new file mode 100644 (file)
index 0000000..20e9db9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cac667320e99e93a796bb89842de4675735eb4a4 differ
diff --git a/fuzzers/corpora/commit_graph/cb41b00e9db33a07e27b3ee05d3bbecaf853b963 b/fuzzers/corpora/commit_graph/cb41b00e9db33a07e27b3ee05d3bbecaf853b963
new file mode 100644 (file)
index 0000000..612843d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cb41b00e9db33a07e27b3ee05d3bbecaf853b963 differ
diff --git a/fuzzers/corpora/commit_graph/cbdbd3f320eee627097778f15b9fb2c1dc2bd15f b/fuzzers/corpora/commit_graph/cbdbd3f320eee627097778f15b9fb2c1dc2bd15f
new file mode 100644 (file)
index 0000000..a922018
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cbdbd3f320eee627097778f15b9fb2c1dc2bd15f differ
diff --git a/fuzzers/corpora/commit_graph/cc7f114000c83abb2ab17f0deab6dcfc2acde7f5 b/fuzzers/corpora/commit_graph/cc7f114000c83abb2ab17f0deab6dcfc2acde7f5
new file mode 100644 (file)
index 0000000..7c9f84c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cc7f114000c83abb2ab17f0deab6dcfc2acde7f5 differ
diff --git a/fuzzers/corpora/commit_graph/cc9bb93a6b7a1362a15f04898845dbe1447ec382 b/fuzzers/corpora/commit_graph/cc9bb93a6b7a1362a15f04898845dbe1447ec382
new file mode 100644 (file)
index 0000000..5dde225
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cc9bb93a6b7a1362a15f04898845dbe1447ec382 differ
diff --git a/fuzzers/corpora/commit_graph/cce7355f826bbcf3955394596d358abc7df6fe6f b/fuzzers/corpora/commit_graph/cce7355f826bbcf3955394596d358abc7df6fe6f
new file mode 100644 (file)
index 0000000..9b78038
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cce7355f826bbcf3955394596d358abc7df6fe6f differ
diff --git a/fuzzers/corpora/commit_graph/cceff2878a558166fb5bf2a0354c1be31dcc4e21 b/fuzzers/corpora/commit_graph/cceff2878a558166fb5bf2a0354c1be31dcc4e21
new file mode 100644 (file)
index 0000000..94fec1b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cceff2878a558166fb5bf2a0354c1be31dcc4e21 differ
diff --git a/fuzzers/corpora/commit_graph/cd96909f3ded7aa54bb2ffd2f2f47f8acc6f99e2 b/fuzzers/corpora/commit_graph/cd96909f3ded7aa54bb2ffd2f2f47f8acc6f99e2
new file mode 100644 (file)
index 0000000..22bbade
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cd96909f3ded7aa54bb2ffd2f2f47f8acc6f99e2 differ
diff --git a/fuzzers/corpora/commit_graph/cee9f69d7d1a227833fba127a529ea2a10341da3 b/fuzzers/corpora/commit_graph/cee9f69d7d1a227833fba127a529ea2a10341da3
new file mode 100644 (file)
index 0000000..2fff45e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/cee9f69d7d1a227833fba127a529ea2a10341da3 differ
diff --git a/fuzzers/corpora/commit_graph/d064f27a3109afde629165432f78f389da73ff07 b/fuzzers/corpora/commit_graph/d064f27a3109afde629165432f78f389da73ff07
new file mode 100644 (file)
index 0000000..e6d98c0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d064f27a3109afde629165432f78f389da73ff07 differ
diff --git a/fuzzers/corpora/commit_graph/d07e3094f02b0c0e3bab370684c2d8c5634224d5 b/fuzzers/corpora/commit_graph/d07e3094f02b0c0e3bab370684c2d8c5634224d5
new file mode 100644 (file)
index 0000000..29d86aa
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d07e3094f02b0c0e3bab370684c2d8c5634224d5 differ
diff --git a/fuzzers/corpora/commit_graph/d0ba3413d5706de17de64824d78233d48c6efbec b/fuzzers/corpora/commit_graph/d0ba3413d5706de17de64824d78233d48c6efbec
new file mode 100644 (file)
index 0000000..96c8207
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d0ba3413d5706de17de64824d78233d48c6efbec differ
diff --git a/fuzzers/corpora/commit_graph/d136511364a74973b009f2be9b021d4122f71a6c b/fuzzers/corpora/commit_graph/d136511364a74973b009f2be9b021d4122f71a6c
new file mode 100644 (file)
index 0000000..a663ab9
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d136511364a74973b009f2be9b021d4122f71a6c differ
diff --git a/fuzzers/corpora/commit_graph/d1d215c40bcc8dd4ce02b0c0621e90b183b40b3e b/fuzzers/corpora/commit_graph/d1d215c40bcc8dd4ce02b0c0621e90b183b40b3e
new file mode 100644 (file)
index 0000000..a328d3e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d1d215c40bcc8dd4ce02b0c0621e90b183b40b3e differ
diff --git a/fuzzers/corpora/commit_graph/d1e35b137b2027b61def408f3f3c8cf9bcab274e b/fuzzers/corpora/commit_graph/d1e35b137b2027b61def408f3f3c8cf9bcab274e
new file mode 100644 (file)
index 0000000..79c43fd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d1e35b137b2027b61def408f3f3c8cf9bcab274e differ
diff --git a/fuzzers/corpora/commit_graph/d349d137e57fb1a60ab8babd20e2acedc7a9042e b/fuzzers/corpora/commit_graph/d349d137e57fb1a60ab8babd20e2acedc7a9042e
new file mode 100644 (file)
index 0000000..981aaf6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d349d137e57fb1a60ab8babd20e2acedc7a9042e differ
diff --git a/fuzzers/corpora/commit_graph/d3714ec4d3acc6262295b0fc99c6ba699f5bfe65 b/fuzzers/corpora/commit_graph/d3714ec4d3acc6262295b0fc99c6ba699f5bfe65
new file mode 100644 (file)
index 0000000..7f6e309
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d3714ec4d3acc6262295b0fc99c6ba699f5bfe65 differ
diff --git a/fuzzers/corpora/commit_graph/d419df696512216074f1c6b17ea1dfc81c0e6e20 b/fuzzers/corpora/commit_graph/d419df696512216074f1c6b17ea1dfc81c0e6e20
new file mode 100644 (file)
index 0000000..47c7019
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d419df696512216074f1c6b17ea1dfc81c0e6e20 differ
diff --git a/fuzzers/corpora/commit_graph/d49ad4fdafac251ceec32481826228c1698360aa b/fuzzers/corpora/commit_graph/d49ad4fdafac251ceec32481826228c1698360aa
new file mode 100644 (file)
index 0000000..9d4756c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d49ad4fdafac251ceec32481826228c1698360aa differ
diff --git a/fuzzers/corpora/commit_graph/d4f85ba549c87ccaba59971a25da7e07b57c9f4e b/fuzzers/corpora/commit_graph/d4f85ba549c87ccaba59971a25da7e07b57c9f4e
new file mode 100644 (file)
index 0000000..e6d72e7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d4f85ba549c87ccaba59971a25da7e07b57c9f4e differ
diff --git a/fuzzers/corpora/commit_graph/d51ade0715bcea7decee2a045934599a10c1b07a b/fuzzers/corpora/commit_graph/d51ade0715bcea7decee2a045934599a10c1b07a
new file mode 100644 (file)
index 0000000..2403b35
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d51ade0715bcea7decee2a045934599a10c1b07a differ
diff --git a/fuzzers/corpora/commit_graph/d5447fb72c97462a3f47c8b2d55deb0afaa225f8 b/fuzzers/corpora/commit_graph/d5447fb72c97462a3f47c8b2d55deb0afaa225f8
new file mode 100644 (file)
index 0000000..07e14a4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d5447fb72c97462a3f47c8b2d55deb0afaa225f8 differ
diff --git a/fuzzers/corpora/commit_graph/d6611a91c29291872ed2932455cb15ddb3801323 b/fuzzers/corpora/commit_graph/d6611a91c29291872ed2932455cb15ddb3801323
new file mode 100644 (file)
index 0000000..361431c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d6611a91c29291872ed2932455cb15ddb3801323 differ
diff --git a/fuzzers/corpora/commit_graph/d676f5e7efd6de6f2e1773231479471d2bba7261 b/fuzzers/corpora/commit_graph/d676f5e7efd6de6f2e1773231479471d2bba7261
new file mode 100644 (file)
index 0000000..f9756ab
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d676f5e7efd6de6f2e1773231479471d2bba7261 differ
diff --git a/fuzzers/corpora/commit_graph/d6a21eaa08a957d8f428192e193c2508fca2c218 b/fuzzers/corpora/commit_graph/d6a21eaa08a957d8f428192e193c2508fca2c218
new file mode 100644 (file)
index 0000000..f845fbb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d6a21eaa08a957d8f428192e193c2508fca2c218 differ
diff --git a/fuzzers/corpora/commit_graph/d778052a29539344a9e3144e262e68df9628ebde b/fuzzers/corpora/commit_graph/d778052a29539344a9e3144e262e68df9628ebde
new file mode 100644 (file)
index 0000000..beace90
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d778052a29539344a9e3144e262e68df9628ebde differ
diff --git a/fuzzers/corpora/commit_graph/d884f6944adfff7cb41728062bf91cac5cdacfc9 b/fuzzers/corpora/commit_graph/d884f6944adfff7cb41728062bf91cac5cdacfc9
new file mode 100644 (file)
index 0000000..f6de651
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d884f6944adfff7cb41728062bf91cac5cdacfc9 differ
diff --git a/fuzzers/corpora/commit_graph/d89aae18d8e320bbae55eaae6a0514d7e005a883 b/fuzzers/corpora/commit_graph/d89aae18d8e320bbae55eaae6a0514d7e005a883
new file mode 100644 (file)
index 0000000..1f0bbf3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d89aae18d8e320bbae55eaae6a0514d7e005a883 differ
diff --git a/fuzzers/corpora/commit_graph/d926fde818c63f7b34f38c9f018bc833bc0bf7e1 b/fuzzers/corpora/commit_graph/d926fde818c63f7b34f38c9f018bc833bc0bf7e1
new file mode 100644 (file)
index 0000000..fe1e274
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d926fde818c63f7b34f38c9f018bc833bc0bf7e1 differ
diff --git a/fuzzers/corpora/commit_graph/d9d542d7c56774143cb6362e5a63739055469349 b/fuzzers/corpora/commit_graph/d9d542d7c56774143cb6362e5a63739055469349
new file mode 100644 (file)
index 0000000..946106f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/d9d542d7c56774143cb6362e5a63739055469349 differ
diff --git a/fuzzers/corpora/commit_graph/da99bc9ce5b831f132dfb2eb11b8537e5cccfcd4 b/fuzzers/corpora/commit_graph/da99bc9ce5b831f132dfb2eb11b8537e5cccfcd4
new file mode 100644 (file)
index 0000000..91ed5b2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/da99bc9ce5b831f132dfb2eb11b8537e5cccfcd4 differ
diff --git a/fuzzers/corpora/commit_graph/dabff2729fa69ab507fb00b7392aee1262056a29 b/fuzzers/corpora/commit_graph/dabff2729fa69ab507fb00b7392aee1262056a29
new file mode 100644 (file)
index 0000000..9318cec
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dabff2729fa69ab507fb00b7392aee1262056a29 differ
diff --git a/fuzzers/corpora/commit_graph/dac4f4b91e33847bcedf7c66ef6e4ad0181e8ad8 b/fuzzers/corpora/commit_graph/dac4f4b91e33847bcedf7c66ef6e4ad0181e8ad8
new file mode 100644 (file)
index 0000000..9587c53
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dac4f4b91e33847bcedf7c66ef6e4ad0181e8ad8 differ
diff --git a/fuzzers/corpora/commit_graph/db10ff6d01c7a66aa1823b9f99193590ddce99c6 b/fuzzers/corpora/commit_graph/db10ff6d01c7a66aa1823b9f99193590ddce99c6
new file mode 100644 (file)
index 0000000..2d8d099
Binary files /dev/null and b/fuzzers/corpora/commit_graph/db10ff6d01c7a66aa1823b9f99193590ddce99c6 differ
diff --git a/fuzzers/corpora/commit_graph/dbbda2208fa688a5275dda0d304630db01ca081d b/fuzzers/corpora/commit_graph/dbbda2208fa688a5275dda0d304630db01ca081d
new file mode 100644 (file)
index 0000000..7edfc3b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dbbda2208fa688a5275dda0d304630db01ca081d differ
diff --git a/fuzzers/corpora/commit_graph/dc47c5037be68a2747ff8a9fa450e1078a5ac5a5 b/fuzzers/corpora/commit_graph/dc47c5037be68a2747ff8a9fa450e1078a5ac5a5
new file mode 100644 (file)
index 0000000..e4ac972
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dc47c5037be68a2747ff8a9fa450e1078a5ac5a5 differ
diff --git a/fuzzers/corpora/commit_graph/dc760f136b123e38677aec72853e3365f08010fc b/fuzzers/corpora/commit_graph/dc760f136b123e38677aec72853e3365f08010fc
new file mode 100644 (file)
index 0000000..855c7b3
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dc760f136b123e38677aec72853e3365f08010fc differ
diff --git a/fuzzers/corpora/commit_graph/dca41b901bf1612d4197e6a450366a00ac036ec3 b/fuzzers/corpora/commit_graph/dca41b901bf1612d4197e6a450366a00ac036ec3
new file mode 100644 (file)
index 0000000..9eec273
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dca41b901bf1612d4197e6a450366a00ac036ec3 differ
diff --git a/fuzzers/corpora/commit_graph/dca62f21fce50d1c8c51b82e0d7eeedc6746e652 b/fuzzers/corpora/commit_graph/dca62f21fce50d1c8c51b82e0d7eeedc6746e652
new file mode 100644 (file)
index 0000000..f8188c6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dca62f21fce50d1c8c51b82e0d7eeedc6746e652 differ
diff --git a/fuzzers/corpora/commit_graph/dcc7e6c444f95b10d634b1137413824e2cd68f62 b/fuzzers/corpora/commit_graph/dcc7e6c444f95b10d634b1137413824e2cd68f62
new file mode 100644 (file)
index 0000000..247d648
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dcc7e6c444f95b10d634b1137413824e2cd68f62 differ
diff --git a/fuzzers/corpora/commit_graph/dcf4b6addda69040f792c9b860ade2af0b77a14c b/fuzzers/corpora/commit_graph/dcf4b6addda69040f792c9b860ade2af0b77a14c
new file mode 100644 (file)
index 0000000..6cbb0b7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dcf4b6addda69040f792c9b860ade2af0b77a14c differ
diff --git a/fuzzers/corpora/commit_graph/dd6178166ac1eed82d132fea491bcda0d953227c b/fuzzers/corpora/commit_graph/dd6178166ac1eed82d132fea491bcda0d953227c
new file mode 100644 (file)
index 0000000..4c13f99
Binary files /dev/null and b/fuzzers/corpora/commit_graph/dd6178166ac1eed82d132fea491bcda0d953227c differ
diff --git a/fuzzers/corpora/commit_graph/ddbd5d3074323ccd7cd70bf5de5a2f30de977d99 b/fuzzers/corpora/commit_graph/ddbd5d3074323ccd7cd70bf5de5a2f30de977d99
new file mode 100644 (file)
index 0000000..646febd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ddbd5d3074323ccd7cd70bf5de5a2f30de977d99 differ
diff --git a/fuzzers/corpora/commit_graph/ddd8ec5632bf1b8153d03a4537d3d76517c497d5 b/fuzzers/corpora/commit_graph/ddd8ec5632bf1b8153d03a4537d3d76517c497d5
new file mode 100644 (file)
index 0000000..e948534
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ddd8ec5632bf1b8153d03a4537d3d76517c497d5 differ
diff --git a/fuzzers/corpora/commit_graph/de7a56f36e10d7b9ff43160b1cea3e76b24386d1 b/fuzzers/corpora/commit_graph/de7a56f36e10d7b9ff43160b1cea3e76b24386d1
new file mode 100644 (file)
index 0000000..6cae1f2
Binary files /dev/null and b/fuzzers/corpora/commit_graph/de7a56f36e10d7b9ff43160b1cea3e76b24386d1 differ
diff --git a/fuzzers/corpora/commit_graph/defa60aa46ea5a47c09b6962b4e4296ef1bcad92 b/fuzzers/corpora/commit_graph/defa60aa46ea5a47c09b6962b4e4296ef1bcad92
new file mode 100644 (file)
index 0000000..2978755
Binary files /dev/null and b/fuzzers/corpora/commit_graph/defa60aa46ea5a47c09b6962b4e4296ef1bcad92 differ
diff --git a/fuzzers/corpora/commit_graph/e0ae419425207832518d66c0ef35d11cbdc20361 b/fuzzers/corpora/commit_graph/e0ae419425207832518d66c0ef35d11cbdc20361
new file mode 100644 (file)
index 0000000..89404f4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e0ae419425207832518d66c0ef35d11cbdc20361 differ
diff --git a/fuzzers/corpora/commit_graph/e0f519accbf15bc57a1bf1d7cc46d2a0b07a67f5 b/fuzzers/corpora/commit_graph/e0f519accbf15bc57a1bf1d7cc46d2a0b07a67f5
new file mode 100644 (file)
index 0000000..af59e9d
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e0f519accbf15bc57a1bf1d7cc46d2a0b07a67f5 differ
diff --git a/fuzzers/corpora/commit_graph/e128eff8ca7572d9bb0bfc84f64d79c52afc2c67 b/fuzzers/corpora/commit_graph/e128eff8ca7572d9bb0bfc84f64d79c52afc2c67
new file mode 100644 (file)
index 0000000..d963f77
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e128eff8ca7572d9bb0bfc84f64d79c52afc2c67 differ
diff --git a/fuzzers/corpora/commit_graph/e17fdc21ae03243bd1d31bb6301b4187cab6fe47 b/fuzzers/corpora/commit_graph/e17fdc21ae03243bd1d31bb6301b4187cab6fe47
new file mode 100644 (file)
index 0000000..381f8e1
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e17fdc21ae03243bd1d31bb6301b4187cab6fe47 differ
diff --git a/fuzzers/corpora/commit_graph/e340ace35a2db7f89d6aa21cc1300766a74be4e1 b/fuzzers/corpora/commit_graph/e340ace35a2db7f89d6aa21cc1300766a74be4e1
new file mode 100644 (file)
index 0000000..00cb20b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e340ace35a2db7f89d6aa21cc1300766a74be4e1 differ
diff --git a/fuzzers/corpora/commit_graph/e36dfc11bcaab1e42df13924a2d7da024684db2e b/fuzzers/corpora/commit_graph/e36dfc11bcaab1e42df13924a2d7da024684db2e
new file mode 100644 (file)
index 0000000..25dd8ea
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e36dfc11bcaab1e42df13924a2d7da024684db2e differ
diff --git a/fuzzers/corpora/commit_graph/e39e0c87ac5ce0b78c89ae2df84226baba666372 b/fuzzers/corpora/commit_graph/e39e0c87ac5ce0b78c89ae2df84226baba666372
new file mode 100644 (file)
index 0000000..acfc881
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e39e0c87ac5ce0b78c89ae2df84226baba666372 differ
diff --git a/fuzzers/corpora/commit_graph/e46b4666c6bfcd6f589ec3617a48cce9c968e833 b/fuzzers/corpora/commit_graph/e46b4666c6bfcd6f589ec3617a48cce9c968e833
new file mode 100644 (file)
index 0000000..92bca77
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e46b4666c6bfcd6f589ec3617a48cce9c968e833 differ
diff --git a/fuzzers/corpora/commit_graph/e57219555e11f9221d3166d5029ed2ad92300608 b/fuzzers/corpora/commit_graph/e57219555e11f9221d3166d5029ed2ad92300608
new file mode 100644 (file)
index 0000000..6f9d153
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e57219555e11f9221d3166d5029ed2ad92300608 differ
diff --git a/fuzzers/corpora/commit_graph/e58ce590c2454e7ebe18e0a31a943b0b754fbd13 b/fuzzers/corpora/commit_graph/e58ce590c2454e7ebe18e0a31a943b0b754fbd13
new file mode 100644 (file)
index 0000000..89d4790
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e58ce590c2454e7ebe18e0a31a943b0b754fbd13 differ
diff --git a/fuzzers/corpora/commit_graph/e595f8fef5c8014cb0867978c6580301078ca0d9 b/fuzzers/corpora/commit_graph/e595f8fef5c8014cb0867978c6580301078ca0d9
new file mode 100644 (file)
index 0000000..339b09e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e595f8fef5c8014cb0867978c6580301078ca0d9 differ
diff --git a/fuzzers/corpora/commit_graph/e5b76398f60628e879328d7009b9fa89feea14cb b/fuzzers/corpora/commit_graph/e5b76398f60628e879328d7009b9fa89feea14cb
new file mode 100644 (file)
index 0000000..6ed637f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e5b76398f60628e879328d7009b9fa89feea14cb differ
diff --git a/fuzzers/corpora/commit_graph/e5cec0217eea93b18a59d76b0aed6b46b13fa6a9 b/fuzzers/corpora/commit_graph/e5cec0217eea93b18a59d76b0aed6b46b13fa6a9
new file mode 100644 (file)
index 0000000..7ae3eb4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e5cec0217eea93b18a59d76b0aed6b46b13fa6a9 differ
diff --git a/fuzzers/corpora/commit_graph/e637b4e0b47d0d6cd870502e6a2d6a53bf917f73 b/fuzzers/corpora/commit_graph/e637b4e0b47d0d6cd870502e6a2d6a53bf917f73
new file mode 100644 (file)
index 0000000..f84ee8c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e637b4e0b47d0d6cd870502e6a2d6a53bf917f73 differ
diff --git a/fuzzers/corpora/commit_graph/e7a6cb6e5a1552837fdbee9025fc48a9373f8564 b/fuzzers/corpora/commit_graph/e7a6cb6e5a1552837fdbee9025fc48a9373f8564
new file mode 100644 (file)
index 0000000..a5ae268
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e7a6cb6e5a1552837fdbee9025fc48a9373f8564 differ
diff --git a/fuzzers/corpora/commit_graph/e7f57c48016e1180c9af95acd34470881f10bd06 b/fuzzers/corpora/commit_graph/e7f57c48016e1180c9af95acd34470881f10bd06
new file mode 100644 (file)
index 0000000..07bbb9c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e7f57c48016e1180c9af95acd34470881f10bd06 differ
diff --git a/fuzzers/corpora/commit_graph/e8253c668bfe37df5c5ada3226860cee74fb33a2 b/fuzzers/corpora/commit_graph/e8253c668bfe37df5c5ada3226860cee74fb33a2
new file mode 100644 (file)
index 0000000..0cb7581
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e8253c668bfe37df5c5ada3226860cee74fb33a2 differ
diff --git a/fuzzers/corpora/commit_graph/e8f9981443c34ece02bca3c66130f3429d7b3375 b/fuzzers/corpora/commit_graph/e8f9981443c34ece02bca3c66130f3429d7b3375
new file mode 100644 (file)
index 0000000..09fe9dd
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e8f9981443c34ece02bca3c66130f3429d7b3375 differ
diff --git a/fuzzers/corpora/commit_graph/e91ed5416bbcd1b03803197b99c08f42c9869139 b/fuzzers/corpora/commit_graph/e91ed5416bbcd1b03803197b99c08f42c9869139
new file mode 100644 (file)
index 0000000..3267ebb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e91ed5416bbcd1b03803197b99c08f42c9869139 differ
diff --git a/fuzzers/corpora/commit_graph/e94201cfa88df7b198abd3abae9007a6780b52a7 b/fuzzers/corpora/commit_graph/e94201cfa88df7b198abd3abae9007a6780b52a7
new file mode 100644 (file)
index 0000000..0279a3c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e94201cfa88df7b198abd3abae9007a6780b52a7 differ
diff --git a/fuzzers/corpora/commit_graph/e967bbd6a0d251ae62c9c38b784271d707f792c0 b/fuzzers/corpora/commit_graph/e967bbd6a0d251ae62c9c38b784271d707f792c0
new file mode 100644 (file)
index 0000000..2baf050
Binary files /dev/null and b/fuzzers/corpora/commit_graph/e967bbd6a0d251ae62c9c38b784271d707f792c0 differ
diff --git a/fuzzers/corpora/commit_graph/ea01737ceed783b3e0f66d9d0c409cb496c1d526 b/fuzzers/corpora/commit_graph/ea01737ceed783b3e0f66d9d0c409cb496c1d526
new file mode 100644 (file)
index 0000000..75c988e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ea01737ceed783b3e0f66d9d0c409cb496c1d526 differ
diff --git a/fuzzers/corpora/commit_graph/ea40f7879a58d1e52a46404c761f76a949e14a31 b/fuzzers/corpora/commit_graph/ea40f7879a58d1e52a46404c761f76a949e14a31
new file mode 100644 (file)
index 0000000..0fe4b30
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ea40f7879a58d1e52a46404c761f76a949e14a31 differ
diff --git a/fuzzers/corpora/commit_graph/ea5ad04a54f95963baea1f47845847626e08dd55 b/fuzzers/corpora/commit_graph/ea5ad04a54f95963baea1f47845847626e08dd55
new file mode 100644 (file)
index 0000000..79a1c4f
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ea5ad04a54f95963baea1f47845847626e08dd55 differ
diff --git a/fuzzers/corpora/commit_graph/ea608a401f54b0ca70e42b897f0c8ce6efdbc0ef b/fuzzers/corpora/commit_graph/ea608a401f54b0ca70e42b897f0c8ce6efdbc0ef
new file mode 100644 (file)
index 0000000..26c55fe
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ea608a401f54b0ca70e42b897f0c8ce6efdbc0ef differ
diff --git a/fuzzers/corpora/commit_graph/eb8700d6b3728e6e70c2a0fe504543771639f2b6 b/fuzzers/corpora/commit_graph/eb8700d6b3728e6e70c2a0fe504543771639f2b6
new file mode 100644 (file)
index 0000000..cf35936
Binary files /dev/null and b/fuzzers/corpora/commit_graph/eb8700d6b3728e6e70c2a0fe504543771639f2b6 differ
diff --git a/fuzzers/corpora/commit_graph/ec1f271b04c322353865f4819153d46df7def873 b/fuzzers/corpora/commit_graph/ec1f271b04c322353865f4819153d46df7def873
new file mode 100644 (file)
index 0000000..95cfa61
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ec1f271b04c322353865f4819153d46df7def873 differ
diff --git a/fuzzers/corpora/commit_graph/ee215536e7f0cfbd07b53dd65c5af9a604a01830 b/fuzzers/corpora/commit_graph/ee215536e7f0cfbd07b53dd65c5af9a604a01830
new file mode 100644 (file)
index 0000000..82241f0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ee215536e7f0cfbd07b53dd65c5af9a604a01830 differ
diff --git a/fuzzers/corpora/commit_graph/ee4d4393d7d79b755f85ef5bf8f6e3d743bfa258 b/fuzzers/corpora/commit_graph/ee4d4393d7d79b755f85ef5bf8f6e3d743bfa258
new file mode 100644 (file)
index 0000000..3d0d7d4
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ee4d4393d7d79b755f85ef5bf8f6e3d743bfa258 differ
diff --git a/fuzzers/corpora/commit_graph/ee8099331b2c392e7e036ffcd4a9b36ec2c2082d b/fuzzers/corpora/commit_graph/ee8099331b2c392e7e036ffcd4a9b36ec2c2082d
new file mode 100644 (file)
index 0000000..4e8f26b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ee8099331b2c392e7e036ffcd4a9b36ec2c2082d differ
diff --git a/fuzzers/corpora/commit_graph/eede9da76db25513f8347f972e170102831de91a b/fuzzers/corpora/commit_graph/eede9da76db25513f8347f972e170102831de91a
new file mode 100644 (file)
index 0000000..d364605
Binary files /dev/null and b/fuzzers/corpora/commit_graph/eede9da76db25513f8347f972e170102831de91a differ
diff --git a/fuzzers/corpora/commit_graph/ef707cdeaa9548b6c820f769c1d8ad607b3c4514 b/fuzzers/corpora/commit_graph/ef707cdeaa9548b6c820f769c1d8ad607b3c4514
new file mode 100644 (file)
index 0000000..31daa3b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ef707cdeaa9548b6c820f769c1d8ad607b3c4514 differ
diff --git a/fuzzers/corpora/commit_graph/ef98609d8196dc158365dfcbbc47e3d1699c50c2 b/fuzzers/corpora/commit_graph/ef98609d8196dc158365dfcbbc47e3d1699c50c2
new file mode 100644 (file)
index 0000000..6cac849
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ef98609d8196dc158365dfcbbc47e3d1699c50c2 differ
diff --git a/fuzzers/corpora/commit_graph/efa38b4269f978f3714b44b501831bea678244e0 b/fuzzers/corpora/commit_graph/efa38b4269f978f3714b44b501831bea678244e0
new file mode 100644 (file)
index 0000000..923b8c5
Binary files /dev/null and b/fuzzers/corpora/commit_graph/efa38b4269f978f3714b44b501831bea678244e0 differ
diff --git a/fuzzers/corpora/commit_graph/efba428e29811d233720ccaaf41966a309312a29 b/fuzzers/corpora/commit_graph/efba428e29811d233720ccaaf41966a309312a29
new file mode 100644 (file)
index 0000000..b803c2e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/efba428e29811d233720ccaaf41966a309312a29 differ
diff --git a/fuzzers/corpora/commit_graph/efd514f056d8d83498b4724249c4623560e0390d b/fuzzers/corpora/commit_graph/efd514f056d8d83498b4724249c4623560e0390d
new file mode 100644 (file)
index 0000000..d0e1a33
Binary files /dev/null and b/fuzzers/corpora/commit_graph/efd514f056d8d83498b4724249c4623560e0390d differ
diff --git a/fuzzers/corpora/commit_graph/f00e449ba67ef15e7f29df1e6948c28155d72baa b/fuzzers/corpora/commit_graph/f00e449ba67ef15e7f29df1e6948c28155d72baa
new file mode 100644 (file)
index 0000000..32153f7
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f00e449ba67ef15e7f29df1e6948c28155d72baa differ
diff --git a/fuzzers/corpora/commit_graph/f0a83929d588466051dced6eae0c387db307d646 b/fuzzers/corpora/commit_graph/f0a83929d588466051dced6eae0c387db307d646
new file mode 100644 (file)
index 0000000..fc53a85
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f0a83929d588466051dced6eae0c387db307d646 differ
diff --git a/fuzzers/corpora/commit_graph/f0e53b72e5d69467e7c014474028ea734f4fcb26 b/fuzzers/corpora/commit_graph/f0e53b72e5d69467e7c014474028ea734f4fcb26
new file mode 100644 (file)
index 0000000..bad38e8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f0e53b72e5d69467e7c014474028ea734f4fcb26 differ
diff --git a/fuzzers/corpora/commit_graph/f186265b3f10f4383f4174e9fb74f0a0cdfa3fca b/fuzzers/corpora/commit_graph/f186265b3f10f4383f4174e9fb74f0a0cdfa3fca
new file mode 100644 (file)
index 0000000..2cc2dd0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f186265b3f10f4383f4174e9fb74f0a0cdfa3fca differ
diff --git a/fuzzers/corpora/commit_graph/f18932fcce5a9db5d6c8f59d622eabc25e255e12 b/fuzzers/corpora/commit_graph/f18932fcce5a9db5d6c8f59d622eabc25e255e12
new file mode 100644 (file)
index 0000000..85c6e0e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f18932fcce5a9db5d6c8f59d622eabc25e255e12 differ
diff --git a/fuzzers/corpora/commit_graph/f2ea163bddb95d67597e2a747779ebf4651cb2a9 b/fuzzers/corpora/commit_graph/f2ea163bddb95d67597e2a747779ebf4651cb2a9
new file mode 100644 (file)
index 0000000..f974087
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f2ea163bddb95d67597e2a747779ebf4651cb2a9 differ
diff --git a/fuzzers/corpora/commit_graph/f2f7d48a6d86143ecb4969808d634163576065b1 b/fuzzers/corpora/commit_graph/f2f7d48a6d86143ecb4969808d634163576065b1
new file mode 100644 (file)
index 0000000..f2ad4a6
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f2f7d48a6d86143ecb4969808d634163576065b1 differ
diff --git a/fuzzers/corpora/commit_graph/f34a833faf2b0dcbae8aaad142c76c7c7e534e99 b/fuzzers/corpora/commit_graph/f34a833faf2b0dcbae8aaad142c76c7c7e534e99
new file mode 100644 (file)
index 0000000..2eaa521
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f34a833faf2b0dcbae8aaad142c76c7c7e534e99 differ
diff --git a/fuzzers/corpora/commit_graph/f5c044ce01645c069334698fb8c4750e44835912 b/fuzzers/corpora/commit_graph/f5c044ce01645c069334698fb8c4750e44835912
new file mode 100644 (file)
index 0000000..a67affa
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f5c044ce01645c069334698fb8c4750e44835912 differ
diff --git a/fuzzers/corpora/commit_graph/f680112645c2502f0612e9d017bbb50cb28affbf b/fuzzers/corpora/commit_graph/f680112645c2502f0612e9d017bbb50cb28affbf
new file mode 100644 (file)
index 0000000..dec09a8
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f680112645c2502f0612e9d017bbb50cb28affbf differ
diff --git a/fuzzers/corpora/commit_graph/f6b778d1b34415a7715905f54968c8b6eb057912 b/fuzzers/corpora/commit_graph/f6b778d1b34415a7715905f54968c8b6eb057912
new file mode 100644 (file)
index 0000000..a93cb66
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f6b778d1b34415a7715905f54968c8b6eb057912 differ
diff --git a/fuzzers/corpora/commit_graph/f6ca6a62dc885c6b2a4b40c4aa1a7cb8118e30bb b/fuzzers/corpora/commit_graph/f6ca6a62dc885c6b2a4b40c4aa1a7cb8118e30bb
new file mode 100644 (file)
index 0000000..29ed04c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f6ca6a62dc885c6b2a4b40c4aa1a7cb8118e30bb differ
diff --git a/fuzzers/corpora/commit_graph/f733a8770c23fde182d2fef7e0d96e67244274d5 b/fuzzers/corpora/commit_graph/f733a8770c23fde182d2fef7e0d96e67244274d5
new file mode 100644 (file)
index 0000000..c6aa758
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f733a8770c23fde182d2fef7e0d96e67244274d5 differ
diff --git a/fuzzers/corpora/commit_graph/f8529ddf17d4505c0932c3d40abe33cbfd8c6f22 b/fuzzers/corpora/commit_graph/f8529ddf17d4505c0932c3d40abe33cbfd8c6f22
new file mode 100644 (file)
index 0000000..f004ecb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f8529ddf17d4505c0932c3d40abe33cbfd8c6f22 differ
diff --git a/fuzzers/corpora/commit_graph/f96f8419a3fc3719ae86d64e1147e7b7f66a2470 b/fuzzers/corpora/commit_graph/f96f8419a3fc3719ae86d64e1147e7b7f66a2470
new file mode 100644 (file)
index 0000000..5dee3ca
Binary files /dev/null and b/fuzzers/corpora/commit_graph/f96f8419a3fc3719ae86d64e1147e7b7f66a2470 differ
diff --git a/fuzzers/corpora/commit_graph/fae241a6c87af37781a3b49e534b7ddb6636eda8 b/fuzzers/corpora/commit_graph/fae241a6c87af37781a3b49e534b7ddb6636eda8
new file mode 100644 (file)
index 0000000..fc4e26b
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fae241a6c87af37781a3b49e534b7ddb6636eda8 differ
diff --git a/fuzzers/corpora/commit_graph/faf8817a04b77c6a976ab0a3d1e905f79bb7f799 b/fuzzers/corpora/commit_graph/faf8817a04b77c6a976ab0a3d1e905f79bb7f799
new file mode 100644 (file)
index 0000000..5164ecb
Binary files /dev/null and b/fuzzers/corpora/commit_graph/faf8817a04b77c6a976ab0a3d1e905f79bb7f799 differ
diff --git a/fuzzers/corpora/commit_graph/fb3e769019fb25d384d4be9d38e4cbce00a6adbc b/fuzzers/corpora/commit_graph/fb3e769019fb25d384d4be9d38e4cbce00a6adbc
new file mode 100644 (file)
index 0000000..008337c
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fb3e769019fb25d384d4be9d38e4cbce00a6adbc differ
diff --git a/fuzzers/corpora/commit_graph/fb9b4b2a46f1c65076340a7bd03b076eb101b760 b/fuzzers/corpora/commit_graph/fb9b4b2a46f1c65076340a7bd03b076eb101b760
new file mode 100644 (file)
index 0000000..8d0c735
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fb9b4b2a46f1c65076340a7bd03b076eb101b760 differ
diff --git a/fuzzers/corpora/commit_graph/fca9b0a398832c9ba02cdc811f625b97d5beb18e b/fuzzers/corpora/commit_graph/fca9b0a398832c9ba02cdc811f625b97d5beb18e
new file mode 100644 (file)
index 0000000..b2681f0
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fca9b0a398832c9ba02cdc811f625b97d5beb18e differ
diff --git a/fuzzers/corpora/commit_graph/fcb1b42c706e61245d5e86f708be777ae63f2772 b/fuzzers/corpora/commit_graph/fcb1b42c706e61245d5e86f708be777ae63f2772
new file mode 100644 (file)
index 0000000..a98b661
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fcb1b42c706e61245d5e86f708be777ae63f2772 differ
diff --git a/fuzzers/corpora/commit_graph/fd6c463e7c30b0e51198c0d1ebbea25f20145e3f b/fuzzers/corpora/commit_graph/fd6c463e7c30b0e51198c0d1ebbea25f20145e3f
new file mode 100644 (file)
index 0000000..b253321
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fd6c463e7c30b0e51198c0d1ebbea25f20145e3f differ
diff --git a/fuzzers/corpora/commit_graph/fdcbaa49097ad120c6d7709b29d5b65b8cf8e719 b/fuzzers/corpora/commit_graph/fdcbaa49097ad120c6d7709b29d5b65b8cf8e719
new file mode 100644 (file)
index 0000000..2167806
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fdcbaa49097ad120c6d7709b29d5b65b8cf8e719 differ
diff --git a/fuzzers/corpora/commit_graph/fe46775b28a2923b8770b44381552a8a1560d875 b/fuzzers/corpora/commit_graph/fe46775b28a2923b8770b44381552a8a1560d875
new file mode 100644 (file)
index 0000000..0acef6e
Binary files /dev/null and b/fuzzers/corpora/commit_graph/fe46775b28a2923b8770b44381552a8a1560d875 differ
diff --git a/fuzzers/corpora/commit_graph/ff04441135ef3308fec2687cf688069c6df8aa31 b/fuzzers/corpora/commit_graph/ff04441135ef3308fec2687cf688069c6df8aa31
new file mode 100644 (file)
index 0000000..33afa05
Binary files /dev/null and b/fuzzers/corpora/commit_graph/ff04441135ef3308fec2687cf688069c6df8aa31 differ
index 905bdd24fa23c4d1a03e400a2ae8ecc639769da3..d9a911419a68706317e4df3d3cc403e755fcae3b 100644 (file)
@@ -25,9 +25,9 @@
 #   contributed code (possibly with some exceptions)
 # "no" means the author does not consent
 # "ask" means that the contributor wants to give/withhold
-#   his/her consent on a patch-by-patch basis.
+#   their consent on a patch-by-patch basis.
 # "???" means the person is a prominent contributor who has
-#   not yet made his/her standpoint clear.
+#   not yet made their standpoint clear.
 #
 # Please try to keep the list alphabetically ordered. It will
 # help in case we get all 600-ish git.git authors on it.
index f39d7fbe2287c49ea0838c25070455b0b897d05d..2961cc3e5de7c232c1e0395b551930e2db446706 100644 (file)
@@ -26,6 +26,7 @@
 #include "git2/deprecated.h"
 #include "git2/describe.h"
 #include "git2/diff.h"
+#include "git2/email.h"
 #include "git2/errors.h"
 #include "git2/filter.h"
 #include "git2/global.h"
index b248eaafea3decb3d8cd2ed3bba057d34fcea36f..bc637df1c2ac591d665d47241abf28c5daf2913c 100644 (file)
@@ -100,6 +100,7 @@ GIT_EXTERN(int) git_apply_options_init(git_apply_options *opts, unsigned int ver
  * @param preimage the tree to apply the diff to
  * @param diff the diff to apply
  * @param options the options for the apply (or null for defaults)
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_apply_to_tree(
        git_index **out,
@@ -137,6 +138,7 @@ typedef enum {
  * @param diff the diff to apply
  * @param location the location to apply (workdir, index or both)
  * @param options the options for the apply (or null for defaults)
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_apply(
        git_repository *repo,
index a3ab5a7a25841aad64f34f450f709c9a49a9b751..3891a0c972995be10d4126b4a9a2bb033611919e 100644 (file)
@@ -130,9 +130,38 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
  *
  * Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes
  * from a `.gitattributes` file in the repository at the HEAD revision.
+ *
+ * Passing the `GIT_ATTR_CHECK_INCLUDE_COMMIT` flag will use attributes
+ * from a `.gitattributes` file in a specific commit.
  */
 #define GIT_ATTR_CHECK_NO_SYSTEM        (1 << 2)
 #define GIT_ATTR_CHECK_INCLUDE_HEAD     (1 << 3)
+#define GIT_ATTR_CHECK_INCLUDE_COMMIT   (1 << 4)
+
+/**
+* An options structure for querying attributes.
+*/
+typedef struct {
+       unsigned int version;
+
+       /** A combination of GIT_ATTR_CHECK flags */
+       unsigned int flags;
+
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
+       git_oid *commit_id;
+#endif
+
+       /**
+        * The commit to load attributes from, when
+        * `GIT_ATTR_CHECK_INCLUDE_COMMIT` is specified.
+        */
+       git_oid attr_commit_id;
+} git_attr_options;
+
+#define GIT_ATTR_OPTIONS_VERSION 1
+#define GIT_ATTR_OPTIONS_INIT {GIT_ATTR_OPTIONS_VERSION}
 
 /**
  * Look up the value of one git attribute for path.
@@ -156,6 +185,28 @@ GIT_EXTERN(int) git_attr_get(
        const char *path,
        const char *name);
 
+/**
+ * Look up the value of one git attribute for path with extended options.
+ *
+ * @param value_out Output of the value of the attribute.  Use the GIT_ATTR_...
+ *             macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just
+ *             use the string value for attributes set to a value.  You
+ *             should NOT modify or free this value.
+ * @param repo The repository containing the path.
+ * @param opts The `git_attr_options` to use when querying these attributes.
+ * @param path The path to check for attributes.  Relative paths are
+ *             interpreted relative to the repo root.  The file does
+ *             not have to exist, but if it does not, then it will be
+ *             treated as a plain file (not a directory).
+ * @param name The name of the attribute to look up.
+ */
+GIT_EXTERN(int) git_attr_get_ext(
+       const char **value_out,
+       git_repository *repo,
+       git_attr_options *opts,
+       const char *path,
+       const char *name);
+
 /**
  * Look up a list of git attributes for path.
  *
@@ -193,6 +244,30 @@ GIT_EXTERN(int) git_attr_get_many(
        size_t num_attr,
        const char **names);
 
+/**
+ * Look up a list of git attributes for path with extended options.
+ *
+ * @param values_out An array of num_attr entries that will have string
+ *             pointers written into it for the values of the attributes.
+ *             You should not modify or free the values that are written
+ *             into this array (although of course, you should free the
+ *             array itself if you allocated it).
+ * @param repo The repository containing the path.
+ * @param opts The `git_attr_options` to use when querying these attributes.
+ * @param path The path inside the repo to check attributes.  This
+ *             does not have to exist, but if it does not, then
+ *             it will be treated as a plain file (i.e. not a directory).
+ * @param num_attr The number of attributes being looked up
+ * @param names An array of num_attr strings containing attribute names.
+ */
+GIT_EXTERN(int) git_attr_get_many_ext(
+       const char **values_out,
+       git_repository *repo,
+       git_attr_options *opts,
+       const char *path,
+       size_t num_attr,
+       const char **names);
+
 /**
  * The callback used with git_attr_foreach.
  *
@@ -231,6 +306,26 @@ GIT_EXTERN(int) git_attr_foreach(
        git_attr_foreach_cb callback,
        void *payload);
 
+/**
+ * Loop over all the git attributes for a path with extended options.
+ *
+ * @param repo The repository containing the path.
+ * @param opts The `git_attr_options` to use when querying these attributes.
+ * @param path Path inside the repo to check attributes.  This does not have
+ *             to exist, but if it does not, then it will be treated as a
+ *             plain file (i.e. not a directory).
+ * @param callback Function to invoke on each attribute name and value.
+ *                 See git_attr_foreach_cb.
+ * @param payload Passed on as extra parameter to callback function.
+ * @return 0 on success, non-zero callback return value, or error code
+ */
+GIT_EXTERN(int) git_attr_foreach_ext(
+       git_repository *repo,
+       git_attr_options *opts,
+       const char *path,
+       git_attr_foreach_cb callback,
+       void *payload);
+
 /**
  * Flush the gitattributes cache.
  *
index f42c8155289807731e6d792145d9ce601956f0b7..d193ce14ed5f2870dfab75032c9b5d3ffb6fa3f8 100644 (file)
@@ -26,27 +26,52 @@ GIT_BEGIN_DECL
 typedef enum {
        /** Normal blame, the default */
        GIT_BLAME_NORMAL = 0,
-       /** Track lines that have moved within a file (like `git blame -M`).
-        * NOT IMPLEMENTED. */
+
+       /**
+        * Track lines that have moved within a file (like `git blame -M`).
+        *
+        * This is not yet implemented and reserved for future use.
+        */
        GIT_BLAME_TRACK_COPIES_SAME_FILE = (1<<0),
-       /** Track lines that have moved across files in the same commit (like `git blame -C`).
-        * NOT IMPLEMENTED. */
+
+       /**
+        * Track lines that have moved across files in the same commit
+        * (like `git blame -C`).
+        *
+        * This is not yet implemented and reserved for future use.
+        */
        GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES = (1<<1),
-       /** Track lines that have been copied from another file that exists in the
-        * same commit (like `git blame -CC`). Implies SAME_FILE.
-        * NOT IMPLEMENTED. */
+
+       /**
+        * Track lines that have been copied from another file that exists
+        * in the same commit (like `git blame -CC`).  Implies SAME_FILE.
+        *
+        * This is not yet implemented and reserved for future use.
+        */
        GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES = (1<<2),
-       /** Track lines that have been copied from another file that exists in *any*
-        * commit (like `git blame -CCC`). Implies SAME_COMMIT_COPIES.
-        * NOT IMPLEMENTED. */
+
+       /**
+        * Track lines that have been copied from another file that exists in
+        * *any* commit (like `git blame -CCC`).  Implies SAME_COMMIT_COPIES.
+        *
+        * This is not yet implemented and reserved for future use.
+        */
        GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = (1<<3),
-       /** Restrict the search of commits to those reachable following only the
-        * first parents. */
+
+       /**
+        * Restrict the search of commits to those reachable following only
+        * the first parents.
+        */
        GIT_BLAME_FIRST_PARENT = (1<<4),
-       /** Use mailmap file to map author and committer names and email addresses
-        * to canonical real names and email addresses. The mailmap will be read
-        * from the working directory, or HEAD in a bare repository. */
+
+       /**
+        * Use mailmap file to map author and committer names and email
+        * addresses to canonical real names and email addresses. The
+        * mailmap will be read from the working directory, or HEAD in a
+        * bare repository.
+        */
        GIT_BLAME_USE_MAILMAP = (1<<5),
+
        /** Ignore whitespace differences */
        GIT_BLAME_IGNORE_WHITESPACE = (1<<6),
 } git_blame_flag_t;
@@ -63,25 +88,33 @@ typedef struct git_blame_options {
 
        /** A combination of `git_blame_flag_t` */
        uint32_t flags;
-       /** The lower bound on the number of alphanumeric
-        *   characters that must be detected as moving/copying within a file for it to
-        *   associate those lines with the parent commit. The default value is 20.
-        *   This value only takes effect if any of the `GIT_BLAME_TRACK_COPIES_*`
-        *   flags are specified.
+
+       /**
+        * The lower bound on the number of alphanumeric characters that
+        * must be detected as moving/copying within a file for it to
+        * associate those lines with the parent commit. The default value
+        * is 20.
+        *
+        * This value only takes effect if any of the `GIT_BLAME_TRACK_COPIES_*`
+        * flags are specified.
         */
        uint16_t min_match_characters;
+
        /** The id of the newest commit to consider. The default is HEAD. */
        git_oid newest_commit;
+
        /**
         * The id of the oldest commit to consider.
         * The default is the first commit encountered with a NULL parent.
         */
        git_oid oldest_commit;
+
        /**
         * The first line in the file to blame.
         * The default is 1 (line numbers start with 1).
         */
        size_t min_line;
+
        /**
         * The last line in the file to blame.
         * The default is the last line of the file.
@@ -108,41 +141,59 @@ GIT_EXTERN(int) git_blame_options_init(
 
 /**
  * Structure that represents a blame hunk.
- *
- * - `lines_in_hunk` is the number of lines in this hunk
- * - `final_commit_id` is the OID of the commit where this line was last
- *   changed.
- * - `final_start_line_number` is the 1-based line number where this hunk
- *   begins, in the final version of the file
- * - `final_signature` is the author of `final_commit_id`. If
- *   `GIT_BLAME_USE_MAILMAP` has been specified, it will contain the canonical
- *    real name and email address.
- * - `orig_commit_id` is the OID of the commit where this hunk was found.  This
- *   will usually be the same as `final_commit_id`, except when
- *   `GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES` has been specified.
- * - `orig_path` is the path to the file where this hunk originated, as of the
- *   commit specified by `orig_commit_id`.
- * - `orig_start_line_number` is the 1-based line number where this hunk begins
- *   in the file named by `orig_path` in the commit specified by
- *   `orig_commit_id`.
- * - `orig_signature` is the author of `orig_commit_id`. If
- *   `GIT_BLAME_USE_MAILMAP` has been specified, it will contain the canonical
- *    real name and email address.
- * - `boundary` is 1 iff the hunk has been tracked to a boundary commit (the
- *   root, or the commit specified in git_blame_options.oldest_commit)
  */
 typedef struct git_blame_hunk {
+       /**
+        * The number of lines in this hunk.
+        */
        size_t lines_in_hunk;
 
+       /**
+        * The OID of the commit where this line was last changed.
+        */
        git_oid final_commit_id;
+
+       /**
+        * The 1-based line number where this hunk begins, in the final version
+        * of the file.
+        */
        size_t final_start_line_number;
+
+       /**
+        * The author of `final_commit_id`. If `GIT_BLAME_USE_MAILMAP` has been
+        * specified, it will contain the canonical real name and email address.
+        */
        git_signature *final_signature;
 
+       /**
+        * The OID of the commit where this hunk was found.
+        * This will usually be the same as `final_commit_id`, except when
+        * `GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES` has been specified.
+        */
        git_oid orig_commit_id;
+
+       /**
+        * The path to the file where this hunk originated, as of the commit
+        * specified by `orig_commit_id`.
+        */
        const char *orig_path;
+
+       /**
+        * The 1-based line number where this hunk begins in the file named by
+        * `orig_path` in the commit specified by `orig_commit_id`.
+        */
        size_t orig_start_line_number;
+
+       /**
+        * The author of `orig_commit_id`. If `GIT_BLAME_USE_MAILMAP` has been
+        * specified, it will contain the canonical real name and email address.
+        */
        git_signature *orig_signature;
 
+       /**
+        * The 1 iff the hunk has been tracked to a boundary commit (the root,
+        * or the commit specified in git_blame_options.oldest_commit)
+        */
        char boundary;
 } git_blame_hunk;
 
index 7e2a745d1cfe6824f486560feb2f275624bd67e6..8fc73919d939efb8dc5ef268ed06604b262ceb5b 100644 (file)
@@ -84,7 +84,7 @@ GIT_EXTERN(git_repository *) git_blob_owner(const git_blob *blob);
  * time.
  *
  * @param blob pointer to the blob
- * @return the pointer
+ * @return the pointer, or NULL on error
  */
 GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob);
 
@@ -113,22 +113,56 @@ typedef enum {
         * When set, filters will be loaded from a `.gitattributes` file
         * in the HEAD commit.
         */
-       GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD = (1 << 2),
+       GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD = (1 << 2),
+
+       /**
+        * When set, filters will be loaded from a `.gitattributes` file
+        * in the specified commit.
+        */
+       GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT = (1 << 3),
 } git_blob_filter_flag_t;
 
 /**
  * The options used when applying filter options to a file.
+ *
+ * Initialize with `GIT_BLOB_FILTER_OPTIONS_INIT`. Alternatively, you can
+ * use `git_blob_filter_options_init`.
+ *
  */
 typedef struct {
        int version;
 
        /** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
        uint32_t flags;
+
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
+       git_oid *commit_id;
+#endif
+
+       /**
+        * The commit to load attributes from, when
+        * `GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
+        */
+       git_oid attr_commit_id;
 } git_blob_filter_options;
 
 #define GIT_BLOB_FILTER_OPTIONS_VERSION 1
 #define GIT_BLOB_FILTER_OPTIONS_INIT {GIT_BLOB_FILTER_OPTIONS_VERSION, GIT_BLOB_FILTER_CHECK_FOR_BINARY}
 
+/**
+ * Initialize git_blob_filter_options structure
+ *
+ * Initializes a `git_blob_filter_options` with default values. Equivalent
+ * to creating an instance with `GIT_BLOB_FILTER_OPTIONS_INIT`.
+ *
+ * @param opts The `git_blob_filter_options` struct to initialize.
+ * @param version The struct version; pass `GIT_BLOB_FILTER_OPTIONS_VERSION`.
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_blob_filter_options_init(git_blob_filter_options *opts, unsigned int version);
+
 /**
  * Get a buffer with the filtered content of a blob.
  *
@@ -229,7 +263,7 @@ GIT_EXTERN(int) git_blob_create_from_stream_commit(
  * Write an in-memory buffer to the ODB as a blob
  *
  * @param id return the id of the written blob
- * @param repo repository where to blob will be written
+ * @param repo repository where the blob will be written
  * @param buffer data to be written into the blob
  * @param len length of the data
  * @return 0 or an error code
index ba6235900d78164ac4e23b9c150a04fafee84689..24ea7f7d0f3709f538ead08d3ea0dcf0b7e74529 100644 (file)
@@ -304,6 +304,31 @@ GIT_EXTERN(int) git_branch_remote_name(
  */
  GIT_EXTERN(int) git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *refname);
 
+/**
+ * Retrieve the upstream merge of a local branch
+ *
+ * This will return the currently configured "branch.*.merge" for a given
+ * branch. This branch must be local.
+ *
+ * @param buf the buffer into which to write the name
+ * @param repo the repository in which to look
+ * @param refname the full name of the branch
+ * @return 0 or an error code
+ */
+ GIT_EXTERN(int) git_branch_upstream_merge(git_buf *buf, git_repository *repo, const char *refname);
+
+/**
+ * Determine whether a branch name is valid, meaning that (when prefixed
+ * with `refs/heads/`) that it is a valid reference name, and that any
+ * additional branch name restrictions are imposed (eg, it cannot start
+ * with a `-`).
+ *
+ * @param valid output pointer to set with validity of given branch name
+ * @param name a branch name to test
+ * @return 0 on success or an error code
+ */
+GIT_EXTERN(int) git_branch_name_is_valid(int *valid, const char *name);
+
 /** @} */
 GIT_END_DECL
 #endif
index e8cd2d1808342e12a6f33da5321fad7b473f0f72..0ed38ffcdd411e6558f13cd47580da965d463911 100644 (file)
@@ -8,6 +8,7 @@
 #define INCLUDE_git_cert_h__
 
 #include "common.h"
+#include "types.h"
 
 /**
  * @file git2/cert.h
@@ -80,8 +81,27 @@ typedef enum {
        GIT_CERT_SSH_SHA1 = (1 << 1),
        /** SHA-256 is available */
        GIT_CERT_SSH_SHA256 = (1 << 2),
+       /** Raw hostkey is available */
+       GIT_CERT_SSH_RAW = (1 << 3),
 } git_cert_ssh_t;
 
+typedef enum {
+       /** The raw key is of an unknown type. */
+       GIT_CERT_SSH_RAW_TYPE_UNKNOWN = 0,
+       /** The raw key is an RSA key. */
+       GIT_CERT_SSH_RAW_TYPE_RSA = 1,
+       /** The raw key is a DSS key. */
+       GIT_CERT_SSH_RAW_TYPE_DSS = 2,
+       /** The raw key is a ECDSA 256 key. */
+       GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 = 3,
+       /** The raw key is a ECDSA 384 key. */
+       GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 = 4,
+       /** The raw key is a ECDSA 521 key. */
+       GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 = 5,
+       /** The raw key is a ED25519 key. */
+       GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 = 6
+} git_cert_ssh_raw_type_t;
+
 /**
  * Hostkey information taken from libssh2
  */
@@ -89,28 +109,45 @@ typedef struct {
        git_cert parent; /**< The parent cert */
 
        /**
-        * A hostkey type from libssh2, either
-        * `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1`
+        * A bitmask containing the available fields.
         */
        git_cert_ssh_t type;
 
        /**
-        * Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will
+        * Hostkey hash. If `type` has `GIT_CERT_SSH_MD5` set, this will
         * have the MD5 hash of the hostkey.
         */
        unsigned char hash_md5[16];
 
        /**
-        * Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will
+        * Hostkey hash. If `type` has `GIT_CERT_SSH_SHA1` set, this will
         * have the SHA-1 hash of the hostkey.
         */
        unsigned char hash_sha1[20];
 
        /**
-        * Hostkey hash. If type has `GIT_CERT_SSH_SHA256` set, this will
+        * Hostkey hash. If `type` has `GIT_CERT_SSH_SHA256` set, this will
         * have the SHA-256 hash of the hostkey.
         */
        unsigned char hash_sha256[32];
+
+       /**
+        * Raw hostkey type. If `type` has `GIT_CERT_SSH_RAW` set, this will
+        * have the type of the raw hostkey.
+        */
+       git_cert_ssh_raw_type_t raw_type;
+
+       /**
+        * Pointer to the raw hostkey. If `type` has `GIT_CERT_SSH_RAW` set,
+        * this will have the raw contents of the hostkey.
+        */
+       const char *hostkey;
+
+       /**
+        * Raw hostkey length. If `type` has `GIT_CERT_SSH_RAW` set, this will
+        * have the length of the raw contents of the hostkey.
+        */
+       size_t hostkey_len;
 } git_cert_hostkey;
 
 /**
index 3c87001bf3341d6d78bf9d3ccaa7981020150439..c7aeee431208c3953e271d3a0cbb0fed503f3ec3 100644 (file)
@@ -177,6 +177,12 @@ typedef enum {
        /** Normally checkout writes the index upon completion; this prevents that. */
        GIT_CHECKOUT_DONT_WRITE_INDEX = (1u << 23),
 
+       /**
+        * Show what would be done by a checkout.  Stop after sending
+        * notifications; don't update the working directory or index.
+        */
+       GIT_CHECKOUT_DRY_RUN = (1u << 24),
+       
        /**
         * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
         */
@@ -194,18 +200,6 @@ typedef enum {
  * Checkout will invoke an options notification callback (`notify_cb`) for
  * certain cases - you pick which ones via `notify_flags`:
  *
- * - GIT_CHECKOUT_NOTIFY_CONFLICT invokes checkout on conflicting paths.
- *
- * - GIT_CHECKOUT_NOTIFY_DIRTY notifies about "dirty" files, i.e. those that
- *   do not need an update but no longer match the baseline.  Core git
- *   displays these files when checkout runs, but won't stop the checkout.
- *
- * - GIT_CHECKOUT_NOTIFY_UPDATED sends notification for any file changed.
- *
- * - GIT_CHECKOUT_NOTIFY_UNTRACKED notifies about untracked files.
- *
- * - GIT_CHECKOUT_NOTIFY_IGNORED notifies about ignored files.
- *
  * Returning a non-zero value from this callback will cancel the checkout.
  * The non-zero return value will be propagated back and returned by the
  * git_checkout_... call.
@@ -216,10 +210,32 @@ typedef enum {
  */
 typedef enum {
        GIT_CHECKOUT_NOTIFY_NONE      = 0,
+
+       /**
+        * Invokes checkout on conflicting paths.
+        */
        GIT_CHECKOUT_NOTIFY_CONFLICT  = (1u << 0),
+
+       /**
+        * Notifies about "dirty" files, i.e. those that do not need an update
+        * but no longer match the baseline.  Core git displays these files when
+        * checkout runs, but won't stop the checkout.
+        */
        GIT_CHECKOUT_NOTIFY_DIRTY     = (1u << 1),
+
+       /**
+        * Sends notification for any file changed.
+        */
        GIT_CHECKOUT_NOTIFY_UPDATED   = (1u << 2),
+
+       /**
+        * Notifies about untracked files.
+        */
        GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3),
+
+       /**
+        * Notifies about ignored files.
+        */
        GIT_CHECKOUT_NOTIFY_IGNORED   = (1u << 4),
 
        GIT_CHECKOUT_NOTIFY_ALL       = 0x0FFFFu
index 2d6f687050fbe41259669c20bb42e7f32171e45d..3c3ea260eff783149f8402091c6475005ff2258c 100644 (file)
@@ -133,7 +133,7 @@ typedef struct git_clone_options {
         * The name of the branch to checkout. NULL means use the
         * remote's default branch.
         */
-       const charcheckout_branch;
+       const char *checkout_branch;
 
        /**
         * A callback used to create the new repository into which to
index e6c4656a9cc0091819454e25d4b6645fc6376939..4d74b8994fc2a281f62dfb0e51ffa35b7b6d59ee 100644 (file)
@@ -503,25 +503,41 @@ GIT_EXTERN(int) git_commit_create_with_signature(
 GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source);
 
 /**
- * Commit signing callback.
- *
- * The callback will be called with the commit content, giving a user an
- * opportunity to sign the commit content. The signature_field
- * buf may be left empty to specify the default field "gpgsig".
- *
- * Signatures can take the form of any string, and can be created on an arbitrary
- * header field. Signatures are most commonly used for verifying authorship of a
- * commit using GPG or a similar cryptographically secure signing algorithm.
- * See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for more
- * details.
- *
- * When the callback:
- * - returns GIT_PASSTHROUGH, no signature will be added to the commit.
- * - returns < 0, commit creation will be aborted.
- * - returns GIT_OK, the signature parameter is expected to be filled.
- */
-typedef int (*git_commit_signing_cb)(
-       git_buf *signature, git_buf *signature_field, const char *commit_content, void *payload);
+ * Commit creation callback: used when a function is going to create
+ * commits (for example, in `git_rebase_commit`) to allow callers to
+ * override the commit creation behavior.  For example, users may
+ * wish to sign commits by providing this information to
+ * `git_commit_create_buffer`, signing that buffer, then calling
+ * `git_commit_create_with_signature`.  The resultant commit id
+ * should be set in the `out` object id parameter.
+ *
+ * @param out pointer that this callback will populate with the object
+ *            id of the commit that is created
+ * @param author the author name and time of the commit
+ * @param committer the committer name and time of the commit
+ * @param message_encoding the encoding of the given message, or NULL
+ *                         to assume UTF8
+ * @param message the commit message
+ * @param tree the tree to be committed
+ * @param parent_count the number of parents for this commit
+ * @param parents the commit parents
+ * @param payload the payload pointer in the rebase options
+ * @return 0 if this callback has created the commit and populated the out
+ *         parameter, GIT_PASSTHROUGH if the callback has not created a
+ *         commit and wants the calling function to create the commit as
+ *         if no callback had been specified, any other value to stop
+ *         and return a failure
+ */
+typedef int (*git_commit_create_cb)(
+       git_oid *out,
+       const git_signature *author,
+       const git_signature *committer,
+       const char *message_encoding,
+       const char *message,
+       const git_tree *tree,
+       size_t parent_count,
+       const git_commit *parents[],
+       void *payload);
 
 /** @} */
 GIT_END_DECL
index 8dd30d506b4bfe0b98c66800061cabdbb580d267..2ee82902529d2373570ecce199f72c21767ba4e3 100644 (file)
@@ -91,10 +91,10 @@ GIT_BEGIN_DECL
 
 /**
  * The separator used in path list strings (ie like in the PATH
- * environment variable). A semi-colon ";" is used on Windows, and
- * a colon ":" for all other systems.
+ * environment variable). A semi-colon ";" is used on Windows and
+ * AmigaOS, and a colon ":" for all other systems.
  */
-#ifdef GIT_WIN32
+#if defined(GIT_WIN32) || defined(AMIGA)
 #define GIT_PATH_LIST_SEPARATOR ';'
 #else
 #define GIT_PATH_LIST_SEPARATOR ':'
@@ -207,7 +207,11 @@ typedef enum {
        GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS,
        GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE,
        GIT_OPT_GET_MWINDOW_FILE_LIMIT,
-       GIT_OPT_SET_MWINDOW_FILE_LIMIT
+       GIT_OPT_SET_MWINDOW_FILE_LIMIT,
+       GIT_OPT_SET_ODB_PACKED_PRIORITY,
+       GIT_OPT_SET_ODB_LOOSE_PRIORITY,
+       GIT_OPT_GET_EXTENSIONS,
+       GIT_OPT_SET_EXTENSIONS
 } git_libgit2_opt_t;
 
 /**
@@ -356,6 +360,11 @@ typedef enum {
  *             >
  *             > - `ciphers` is the list of ciphers that are eanbled.
  *
+ *     * opts(GIT_OPT_GET_USER_AGENT, git_buf *out)
+ *
+ *             > Get the value of the User-Agent header.
+ *             > The User-Agent is written to the `out` buffer.
+ *
  *     * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled)
  *
  *             > Enable or disable the use of "offset deltas" when creating packfiles,
@@ -416,6 +425,30 @@ typedef enum {
  *             > authentication, use expect/continue when POSTing data.
  *             > This option is not available on Windows.
  *
+ *   opts(GIT_OPT_SET_ODB_PACKED_PRIORITY, int priority)
+ *      > Override the default priority of the packed ODB backend which
+ *      > is added when default backends are assigned to a repository
+ *
+ *   opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY, int priority)
+ *      > Override the default priority of the loose ODB backend which
+ *      > is added when default backends are assigned to a repository
+ *
+ *   opts(GIT_OPT_GET_EXTENSIONS, git_strarray *out)
+ *      > Returns the list of git extensions that are supported.  This
+ *      > is the list of built-in extensions supported by libgit2 and
+ *      > custom extensions that have been added with
+ *      > `GIT_OPT_SET_EXTENSIONS`.  Extensions that have been negated
+ *      > will not be returned.  The returned list should be released
+ *      > with `git_strarray_dispose`.
+ *
+ *   opts(GIT_OPT_SET_EXTENSIONS, const char **extensions, size_t len)
+ *      > Set that the given git extensions are supported by the caller.
+ *      > Extensions supported by libgit2 may be negated by prefixing
+ *      > them with a `!`.  For example: setting extensions to
+ *      > { "!noop", "newext" } indicates that the caller does not want
+ *      > to support repositories with the `noop` extension but does want
+ *      > to support repositories with the `newext` extension.
+ *
  * @param option Option key
  * @param ... value to set the option
  * @return 0 on success, <0 on failure
index abf5bbbd02e5e2ab9caea621fd71a0c5967bf610..7c8e388b2379177a935ac74cf41a723a8a8dc64b 100644 (file)
@@ -263,7 +263,7 @@ GIT_EXTERN(int) git_config_open_level(
  *
  * Git allows you to store your global configuration at
  * `$HOME/.gitconfig` or `$XDG_CONFIG_HOME/git/config`. For backwards
- * compatability, the XDG file shouldn't be used unless the use has
+ * compatibility, the XDG file shouldn't be used unless the use has
  * created it explicitly. With this function you'll open the correct
  * one to write to.
  *
index 3f285018d26bdb23af11dc707374c030fe7ed245..37b9fa0e2f1549bb64a83f6dc551a29715676b77 100644 (file)
@@ -18,6 +18,7 @@
 #include "describe.h"
 #include "diff.h"
 #include "errors.h"
+#include "filter.h"
 #include "index.h"
 #include "indexer.h"
 #include "merge.h"
@@ -29,6 +30,7 @@
 #include "trace.h"
 #include "repository.h"
 #include "revert.h"
+#include "revparse.h"
 #include "stash.h"
 #include "status.h"
 #include "submodule.h"
@@ -80,16 +82,19 @@ typedef git_attr_value_t git_attr_t;
 
 /**@}*/
 
-/** @name Deprecated Blob Functions
+/** @name Deprecated Blob Functions and Constants
  *
- * These functions are retained for backward compatibility.  The newer
- * versions of these functions should be preferred in all new code.
+ * These functions and enumeration values are retained for backward
+ * compatibility.  The newer versions of these functions and values
+ * should be preferred in all new code.
  *
  * There is no plan to remove these backward compatibility values at
  * this time.
  */
 /**@{*/
 
+#define GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD
+
 GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path);
 GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path);
 GIT_EXTERN(int) git_blob_create_fromstream(
@@ -115,6 +120,66 @@ GIT_EXTERN(int) git_blob_filtered_content(
 
 /**@}*/
 
+/** @name Deprecated Filter Functions
+ *
+ * These functions are retained for backward compatibility.  The
+ * newer versions of these functions should be preferred in all
+ * new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/** Deprecated in favor of `git_filter_list_stream_buffer`.
+ *
+ * @deprecated Use git_filter_list_stream_buffer
+ * @see Use git_filter_list_stream_buffer
+ */
+GIT_EXTERN(int) git_filter_list_stream_data(
+       git_filter_list *filters,
+       git_buf *data,
+       git_writestream *target);
+
+/** Deprecated in favor of `git_filter_list_apply_to_buffer`.
+ *
+ * @deprecated Use git_filter_list_apply_to_buffer
+ * @see Use git_filter_list_apply_to_buffer
+ */
+GIT_EXTERN(int) git_filter_list_apply_to_data(
+       git_buf *out,
+       git_filter_list *filters,
+       git_buf *in);
+
+/**@}*/
+
+/** @name Deprecated Tree Functions
+ *
+ * These functions are retained for backward compatibility.  The
+ * newer versions of these functions and values should be preferred
+ * in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * Write the contents of the tree builder as a tree object.
+ * This is an alias of `git_treebuilder_write` and is preserved
+ * for backward compatibility.
+ *
+ * This function is deprecated, but there is no plan to remove this
+ * function at this time.
+ *
+ * @deprecated Use git_treebuilder_write
+ * @see git_treebuilder_write
+ */
+GIT_EXTERN(int) git_treebuilder_write_with_buffer(
+       git_oid *oid, git_treebuilder *bld, git_buf *tree);
+
+/**@}*/
+
 /** @name Deprecated Buffer Functions
  *
  * These functions and enumeration values are retained for backward
@@ -126,6 +191,61 @@ GIT_EXTERN(int) git_blob_filtered_content(
  */
 /**@{*/
 
+/**
+ * Static initializer for git_buf from static buffer
+ */
+#define GIT_BUF_INIT_CONST(STR,LEN) { (char *)(STR), 0, (size_t)(LEN) }
+
+/**
+ * Resize the buffer allocation to make more space.
+ *
+ * This will attempt to grow the buffer to accommodate the target size.
+ *
+ * If the buffer refers to memory that was not allocated by libgit2 (i.e.
+ * the `asize` field is zero), then `ptr` will be replaced with a newly
+ * allocated block of data.  Be careful so that memory allocated by the
+ * caller is not lost.  As a special variant, if you pass `target_size` as
+ * 0 and the memory is not allocated by libgit2, this will allocate a new
+ * buffer of size `size` and copy the external data into it.
+ *
+ * Currently, this will never shrink a buffer, only expand it.
+ *
+ * If the allocation fails, this will return an error and the buffer will be
+ * marked as invalid for future operations, invaliding the contents.
+ *
+ * @param buffer The buffer to be resized; may or may not be allocated yet
+ * @param target_size The desired available size
+ * @return 0 on success, -1 on allocation failure
+ */
+GIT_EXTERN(int) git_buf_grow(git_buf *buffer, size_t target_size);
+
+/**
+ * Set buffer to a copy of some raw data.
+ *
+ * @param buffer The buffer to set
+ * @param data The data to copy into the buffer
+ * @param datalen The length of the data to copy into the buffer
+ * @return 0 on success, -1 on allocation failure
+ */
+GIT_EXTERN(int) git_buf_set(
+       git_buf *buffer, const void *data, size_t datalen);
+
+/**
+* Check quickly if buffer looks like it contains binary data
+*
+* @param buf Buffer to check
+* @return 1 if buffer looks like non-text data
+*/
+GIT_EXTERN(int) git_buf_is_binary(const git_buf *buf);
+
+/**
+* Check quickly if buffer contains a NUL byte
+*
+* @param buf Buffer to check
+* @return 1 if buffer contains a NUL byte
+*/
+GIT_EXTERN(int) git_buf_contains_nul(const git_buf *buf);
+
 /**
  * Free the memory referred to by the git_buf.  This is an alias of
  * `git_buf_dispose` and is preserved for backward compatibility.
@@ -140,6 +260,27 @@ GIT_EXTERN(void) git_buf_free(git_buf *buffer);
 
 /**@}*/
 
+/** @name Deprecated Commit Definitions
+ */
+/**@{*/
+
+/**
+ * Provide a commit signature during commit creation.
+ *
+ * Callers should instead define a `git_commit_create_cb` that
+ * generates a commit buffer using `git_commit_create_buffer`, sign
+ * that buffer and call `git_commit_create_with_signature`.
+ *
+ * @deprecated use a `git_commit_create_cb` instead
+ */
+typedef int (*git_commit_signing_cb)(
+       git_buf *signature,
+       git_buf *signature_field,
+       const char *commit_content,
+       void *payload);
+
+/**@}*/
+
 /** @name Deprecated Config Functions and Constants
  */
 /**@{*/
@@ -153,6 +294,102 @@ typedef git_configmap git_cvar_map;
 
 /**@}*/
 
+/** @name Deprecated Diff Functions and Constants
+ *
+ * These functions and enumeration values are retained for backward
+ * compatibility.  The newer versions of these functions and values
+ * should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * Formatting options for diff e-mail generation
+ */
+typedef enum {
+       /** Normal patch, the default */
+       GIT_DIFF_FORMAT_EMAIL_NONE = 0,
+
+       /** Don't insert "[PATCH]" in the subject header*/
+       GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0),
+
+} git_diff_format_email_flags_t;
+
+/**
+ * Options for controlling the formatting of the generated e-mail.
+ */
+typedef struct {
+       unsigned int version;
+
+       /** see `git_diff_format_email_flags_t` above */
+       uint32_t flags;
+
+       /** This patch number */
+       size_t patch_no;
+
+       /** Total number of patches in this series */
+       size_t total_patches;
+
+       /** id to use for the commit */
+       const git_oid *id;
+
+       /** Summary of the change */
+       const char *summary;
+
+       /** Commit message's body */
+       const char *body;
+
+       /** Author of the change */
+       const git_signature *author;
+} git_diff_format_email_options;
+
+#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1
+#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL, NULL}
+
+/**
+ * Create an e-mail ready patch from a diff.
+ *
+ * @deprecated git_email_create_from_diff
+ * @see git_email_create_from_diff
+ */
+GIT_EXTERN(int) git_diff_format_email(
+       git_buf *out,
+       git_diff *diff,
+       const git_diff_format_email_options *opts);
+
+/**
+ * Create an e-mail ready patch for a commit.
+ *
+ * @deprecated git_email_create_from_commit
+ * @see git_email_create_from_commit
+ */
+GIT_EXTERN(int) git_diff_commit_as_email(
+       git_buf *out,
+       git_repository *repo,
+       git_commit *commit,
+       size_t patch_no,
+       size_t total_patches,
+       uint32_t flags,
+       const git_diff_options *diff_opts);
+
+/**
+ * Initialize git_diff_format_email_options structure
+ *
+ * Initializes a `git_diff_format_email_options` with default values. Equivalent
+ * to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
+ *
+ * @param opts The `git_blame_options` struct to initialize.
+ * @param version The struct version; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`.
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_diff_format_email_options_init(
+       git_diff_format_email_options *opts,
+       unsigned int version);
+
+/**@}*/
+
 /** @name Deprecated Error Functions and Constants
  *
  * These functions and enumeration values are retained for backward
@@ -340,10 +577,32 @@ GIT_EXTERN(size_t) git_object__size(git_object_t type);
 
 /**@}*/
 
-/** @name Deprecated Reference Constants
+/** @name Deprecated Remote Functions
  *
- * These enumeration values are retained for backward compatibility.  The
- * newer versions of these values should be preferred in all new code.
+ * These functions are retained for backward compatibility.  The newer
+ * versions of these functions should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility functions at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * Ensure the remote name is well-formed.
+ *
+ * @deprecated Use git_remote_name_is_valid
+ * @param remote_name name to be checked.
+ * @return 1 if the reference name is acceptable; 0 if it isn't
+ */
+GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
+
+/**@}*/
+
+/** @name Deprecated Reference Functions and Constants
+ *
+ * These functions and enumeration values are retained for backward
+ * compatibility.  The newer versions of these values should be
+ * preferred in all new code.
  *
  * There is no plan to remove these backward compatibility values at
  * this time.
@@ -364,6 +623,23 @@ GIT_EXTERN(size_t) git_object__size(git_object_t type);
 #define GIT_REF_FORMAT_REFSPEC_PATTERN GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
 #define GIT_REF_FORMAT_REFSPEC_SHORTHAND GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND
 
+/**
+ * Ensure the reference name is well-formed.
+ *
+ * Valid reference names must follow one of two patterns:
+ *
+ * 1. Top-level names must contain only capital letters and underscores,
+ *    and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD").
+ * 2. Names prefixed with "refs/" can be almost anything.  You must avoid
+ *    the characters '~', '^', ':', '\\', '?', '[', and '*', and the
+ *    sequences ".." and "@{" which have special meaning to revparse.
+ *
+ * @deprecated Use git_reference_name_is_valid
+ * @param refname name to be checked.
+ * @return 1 if the reference name is acceptable; 0 if it isn't
+ */
+GIT_EXTERN(int) git_reference_is_valid_name(const char *refname);
+
 GIT_EXTERN(int) git_tag_create_frombuffer(
        git_oid *oid,
        git_repository *repo,
@@ -372,6 +648,25 @@ GIT_EXTERN(int) git_tag_create_frombuffer(
 
 /**@}*/
 
+/** @name Deprecated Revspec Constants
+ *
+ * These enumeration values are retained for backward compatibility.
+ * The newer versions of these values should be preferred in all new
+ * code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+typedef git_revspec_t git_revparse_mode_t;
+
+#define GIT_REVPARSE_SINGLE GIT_REVSPEC_SINGLE
+#define GIT_REVPARSE_RANGE GIT_REVSPEC_RANGE
+#define GIT_REVPARSE_MERGE_BASE GIT_REVSPEC_MERGE_BASE
+
+/**@}*/
+
 /** @name Deprecated Credential Types
  *
  * These types are retained for backward compatibility.  The newer
@@ -380,6 +675,7 @@ GIT_EXTERN(int) git_tag_create_frombuffer(
  * There is no plan to remove these backward compatibility values at
  * this time.
  */
+/**@{*/
 
 typedef git_credential git_cred;
 typedef git_credential_userpass_plaintext git_cred_userpass_plaintext;
@@ -483,6 +779,30 @@ GIT_EXTERN(int) git_oid_iszero(const git_oid *id);
 
 /**@}*/
 
+/** @name Deprecated OID Array Functions
+ *
+ * These types are retained for backward compatibility.  The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * Free the memory referred to by the git_oidarray.  This is an alias of
+ * `git_oidarray_dispose` and is preserved for backward compatibility.
+ *
+ * This function is deprecated, but there is no plan to remove this
+ * function at this time.
+ *
+ * @deprecated Use git_oidarray_dispose
+ * @see git_oidarray_dispose
+ */
+GIT_EXTERN(void) git_oidarray_free(git_oidarray *array);
+
+/**@}*/
+
 /** @name Deprecated Transfer Progress Types
  *
  * These types are retained for backward compatibility.  The newer
index 3976ab1b9195602fa9011e10e27abbc35fe0324b..a14c01993faca354582b8fba59c838f11ad4082e 100644 (file)
@@ -133,6 +133,9 @@ typedef enum {
         */
        GIT_DIFF_INDENT_HEURISTIC = (1u << 18),
 
+       /** Ignore blank lines */
+       GIT_DIFF_IGNORE_BLANK_LINES = (1u << 19),
+
        /** Treat all files as text, disabling binary attributes & detection */
        GIT_DIFF_FORCE_TEXT = (1u << 20),
        /** Treat all files as binary, disabling text diffs */
@@ -237,32 +240,43 @@ typedef enum {
  * Although this is called a "file", it could represent a file, a symbolic
  * link, a submodule commit id, or even a tree (although that only if you
  * are tracking type changes or ignored/untracked directories).
- *
- * The `id` is the `git_oid` of the item.  If the entry represents an
- * absent side of a diff (e.g. the `old_file` of a `GIT_DELTA_ADDED` delta),
- * then the oid will be zeroes.
- *
- * `path` is the NUL-terminated path to the entry relative to the working
- * directory of the repository.
- *
- * `size` is the size of the entry in bytes.
- *
- * `flags` is a combination of the `git_diff_flag_t` types
- *
- * `mode` is, roughly, the stat() `st_mode` value for the item.  This will
- * be restricted to one of the `git_filemode_t` values.
- *
- * The `id_abbrev` represents the known length of the `id` field, when
- * converted to a hex string.  It is generally `GIT_OID_HEXSZ`, unless this
- * delta was created from reading a patch file, in which case it may be
- * abbreviated to something reasonable, like 7 characters.
  */
 typedef struct {
+       /**
+        * The `git_oid` of the item.  If the entry represents an
+        * absent side of a diff (e.g. the `old_file` of a `GIT_DELTA_ADDED` delta),
+        * then the oid will be zeroes.
+        */
        git_oid            id;
+
+       /**
+        * The NUL-terminated path to the entry relative to the working
+        * directory of the repository.
+        */
        const char        *path;
+
+       /**
+        * The size of the entry in bytes.
+        */
        git_object_size_t  size;
+
+       /**
+        * A combination of the `git_diff_flag_t` types
+        */
        uint32_t           flags;
+
+       /**
+        * Roughly, the stat() `st_mode` value for the item.  This will
+        * be restricted to one of the `git_filemode_t` values.
+        */
        uint16_t           mode;
+
+       /**
+        * Represents the known length of the `id` field, when
+        * converted to a hex string.  It is generally `GIT_OID_HEXSZ`, unless this
+        * delta was created from reading a patch file, in which case it may be
+        * abbreviated to something reasonable, like 7 characters.
+        */
        uint16_t           id_abbrev;
 } git_diff_file;
 
@@ -998,7 +1012,7 @@ GIT_EXTERN(size_t) git_diff_num_deltas(const git_diff *diff);
 /**
  * Query how many diff deltas are there in a diff filtered by type.
  *
- * This works just like `git_diff_entrycount()` with an extra parameter
+ * This works just like `git_diff_num_deltas()` with an extra parameter
  * that is a `git_delta_t` and returns just the count of how many deltas
  * match that particular type.
  *
@@ -1361,99 +1375,6 @@ GIT_EXTERN(int) git_diff_stats_to_buf(
  */
 GIT_EXTERN(void) git_diff_stats_free(git_diff_stats *stats);
 
-/**
- * Formatting options for diff e-mail generation
- */
-typedef enum {
-       /** Normal patch, the default */
-       GIT_DIFF_FORMAT_EMAIL_NONE = 0,
-
-       /** Don't insert "[PATCH]" in the subject header*/
-       GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0),
-
-} git_diff_format_email_flags_t;
-
-/**
- * Options for controlling the formatting of the generated e-mail.
- */
-typedef struct {
-       unsigned int version;
-
-       /** see `git_diff_format_email_flags_t` above */
-       uint32_t flags;
-
-       /** This patch number */
-       size_t patch_no;
-
-       /** Total number of patches in this series */
-       size_t total_patches;
-
-       /** id to use for the commit */
-       const git_oid *id;
-
-       /** Summary of the change */
-       const char *summary;
-
-       /** Commit message's body */
-       const char *body;
-
-       /** Author of the change */
-       const git_signature *author;
-} git_diff_format_email_options;
-
-#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1
-#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL, NULL}
-
-/**
- * Create an e-mail ready patch from a diff.
- *
- * @param out buffer to store the e-mail patch in
- * @param diff containing the commit
- * @param opts structure with options to influence content and formatting.
- * @return 0 or an error code
- */
-GIT_EXTERN(int) git_diff_format_email(
-       git_buf *out,
-       git_diff *diff,
-       const git_diff_format_email_options *opts);
-
-/**
- * Create an e-mail ready patch for a commit.
- *
- * Does not support creating patches for merge commits (yet).
- *
- * @param out buffer to store the e-mail patch in
- * @param repo containing the commit
- * @param commit pointer to up commit
- * @param patch_no patch number of the commit
- * @param total_patches total number of patches in the patch set
- * @param flags determines the formatting of the e-mail
- * @param diff_opts structure with options to influence diff or NULL for defaults.
- * @return 0 or an error code
- */
-GIT_EXTERN(int) git_diff_commit_as_email(
-       git_buf *out,
-       git_repository *repo,
-       git_commit *commit,
-       size_t patch_no,
-       size_t total_patches,
-       uint32_t flags,
-       const git_diff_options *diff_opts);
-
-/**
- * Initialize git_diff_format_email_options structure
- *
- * Initializes a `git_diff_format_email_options` with default values. Equivalent
- * to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
- *
- * @param opts The `git_blame_options` struct to initialize.
- * @param version The struct version; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`.
- * @return Zero on success; -1 on failure.
- */
-GIT_EXTERN(int) git_diff_format_email_options_init(
-       git_diff_format_email_options *opts,
-       unsigned int version);
-
 /**
  * Patch ID options structure
  *
diff --git a/include/git2/email.h b/include/git2/email.h
new file mode 100644 (file)
index 0000000..b56be5d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_email_h__
+#define INCLUDE_git_email_h__
+
+#include "common.h"
+
+/**
+ * @file git2/email.h
+ * @brief Git email formatting and application routines.
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Formatting options for diff e-mail generation
+ */
+typedef enum {
+       /** Normal patch, the default */
+       GIT_EMAIL_CREATE_DEFAULT = 0,
+
+       /** Do not include patch numbers in the subject prefix. */
+       GIT_EMAIL_CREATE_OMIT_NUMBERS = (1u << 0),
+
+       /**
+        * Include numbers in the subject prefix even when the
+        * patch is for a single commit (1/1).
+        */
+       GIT_EMAIL_CREATE_ALWAYS_NUMBER = (1u << 1),
+
+       /** Do not perform rename or similarity detection. */
+       GIT_EMAIL_CREATE_NO_RENAMES = (1u << 2),
+} git_email_create_flags_t;
+
+/**
+ * Options for controlling the formatting of the generated e-mail.
+ */
+typedef struct {
+       unsigned int version;
+
+       /** see `git_email_create_flags_t` above */
+       uint32_t flags;
+
+       /** Options to use when creating diffs */
+       git_diff_options diff_opts;
+
+       /** Options for finding similarities within diffs */
+       git_diff_find_options diff_find_opts;
+
+       /**
+        * The subject prefix, by default "PATCH".  If set to an empty
+        * string ("") then only the patch numbers will be shown in the
+        * prefix.  If the subject_prefix is empty and patch numbers
+        * are not being shown, the prefix will be omitted entirely.
+        */
+       const char *subject_prefix;
+
+       /**
+        * The starting patch number; this cannot be 0.  By default,
+        * this is 1.
+        */
+       size_t start_number;
+
+       /** The "re-roll" number.  By default, there is no re-roll. */
+       size_t reroll_number;
+} git_email_create_options;
+
+/*
+ * By default, our options include rename detection and binary
+ * diffs to match `git format-patch`.
+ */
+#define GIT_EMAIL_CREATE_OPTIONS_VERSION 1
+#define GIT_EMAIL_CREATE_OPTIONS_INIT \
+{ \
+       GIT_EMAIL_CREATE_OPTIONS_VERSION, \
+       GIT_EMAIL_CREATE_DEFAULT, \
+       { GIT_DIFF_OPTIONS_VERSION, GIT_DIFF_SHOW_BINARY, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL,0}, NULL, NULL, NULL, 3 }, \
+       GIT_DIFF_FIND_OPTIONS_INIT \
+}
+
+/**
+ * Create a diff for a commit in mbox format for sending via email.
+ *
+ * @param out buffer to store the e-mail patch in
+ * @param diff the changes to include in the email
+ * @param patch_idx the patch index
+ * @param patch_count the total number of patches that will be included
+ * @param commit_id the commit id for this change
+ * @param summary the commit message for this change
+ * @param body optional text to include above the diffstat
+ * @param author the person who authored this commit
+ * @param opts email creation options
+ */
+GIT_EXTERN(int) git_email_create_from_diff(
+       git_buf *out,
+       git_diff *diff,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const char *body,
+       const git_signature *author,
+       const git_email_create_options *opts);
+
+/**
+ * Create a diff for a commit in mbox format for sending via email.
+ * The commit must not be a merge commit.
+ *
+ * @param out buffer to store the e-mail patch in
+ * @param commit commit to create a patch for
+ * @param opts email creation options
+ */
+GIT_EXTERN(int) git_email_create_from_commit(
+       git_buf *out,
+       git_commit *commit,
+       const git_email_create_options *opts);
+
+GIT_END_DECL
+
+/** @} */
+
+#endif
index 8887b3299017e706f79d956655068ca3780488c2..de51582d58ec7b340bd510a15bfb80033221ba4a 100644 (file)
@@ -42,14 +42,14 @@ typedef enum {
        GIT_ECONFLICT       = -13,      /**< Checkout conflicts prevented operation */
        GIT_ELOCKED         = -14,      /**< Lock file prevented operation */
        GIT_EMODIFIED       = -15,      /**< Reference value does not match expected */
-       GIT_EAUTH           = -16,      /**< Authentication error */
-       GIT_ECERTIFICATE    = -17,      /**< Server certificate is invalid */
+       GIT_EAUTH           = -16,      /**< Authentication error */
+       GIT_ECERTIFICATE    = -17,      /**< Server certificate is invalid */
        GIT_EAPPLIED        = -18,      /**< Patch/merge has already been applied */
-       GIT_EPEEL           = -19,      /**< The requested peel operation is not possible */
-       GIT_EEOF            = -20,      /**< Unexpected EOF */
-       GIT_EINVALID        = -21,      /**< Invalid operation or input */
+       GIT_EPEEL           = -19,      /**< The requested peel operation is not possible */
+       GIT_EEOF            = -20,      /**< Unexpected EOF */
+       GIT_EINVALID        = -21,      /**< Invalid operation or input */
        GIT_EUNCOMMITTED    = -22,      /**< Uncommitted changes in index prevented operation */
-       GIT_EDIRECTORY      = -23,      /**< The operation is not valid for a directory */
+       GIT_EDIRECTORY      = -23,      /**< The operation is not valid for a directory */
        GIT_EMERGECONFLICT  = -24,      /**< A merge conflict exists and cannot continue */
 
        GIT_PASSTHROUGH     = -30,      /**< A user-configured callback refused to act */
index 8860590515ca1e8f784d3774b333b512e75ab5b0..0465e5b144ad27de41ce639736483208a4673f02 100644 (file)
@@ -49,8 +49,39 @@ typedef enum {
 
        /** Load attributes from `.gitattributes` in the root of HEAD */
        GIT_FILTER_ATTRIBUTES_FROM_HEAD = (1u << 2),
+
+       /**
+        * Load attributes from `.gitattributes` in a given commit.
+        * This can only be specified in a `git_filter_options`.
+        */
+       GIT_FILTER_ATTRIBUTES_FROM_COMMIT = (1u << 3),
 } git_filter_flag_t;
 
+/**
+ * Filtering options
+ */
+typedef struct {
+       unsigned int version;
+
+       /** See `git_filter_flag_t` above */
+       uint32_t flags;
+
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
+       git_oid *commit_id;
+#endif
+
+       /**
+        * The commit to load attributes from, when
+        * `GIT_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
+        */
+       git_oid attr_commit_id;
+} git_filter_options;
+
+ #define GIT_FILTER_OPTIONS_VERSION 1
+ #define GIT_FILTER_OPTIONS_INIT {GIT_FILTER_OPTIONS_VERSION}
+
 /**
  * A filter that can transform file data
  *
@@ -103,6 +134,29 @@ GIT_EXTERN(int) git_filter_list_load(
        git_filter_mode_t mode,
        uint32_t flags);
 
+/**
+ * Load the filter list for a given path.
+ *
+ * This will return 0 (success) but set the output git_filter_list to NULL
+ * if no filters are requested for the given file.
+ *
+ * @param filters Output newly created git_filter_list (or NULL)
+ * @param repo Repository object that contains `path`
+ * @param blob The blob to which the filter will be applied (if known)
+ * @param path Relative path of the file to be filtered
+ * @param mode Filtering direction (WT->ODB or ODB->WT)
+ * @param opts The `git_filter_options` to use when loading filters
+ * @return 0 on success (which could still return NULL if no filters are
+ *         needed for the requested file), <0 on error
+ */
+GIT_EXTERN(int) git_filter_list_load_ext(
+       git_filter_list **filters,
+       git_repository *repo,
+       git_blob *blob,
+       const char *path,
+       git_filter_mode_t mode,
+       git_filter_options *opts);
+
 /**
  * Query the filter list to see if a given filter (by name) will run.
  * The built-in filters "crlf" and "ident" can be queried, otherwise this
@@ -122,27 +176,17 @@ GIT_EXTERN(int) git_filter_list_contains(
 /**
  * Apply filter list to a data buffer.
  *
- * See `git2/buffer.h` for background on `git_buf` objects.
- *
- * If the `in` buffer holds data allocated by libgit2 (i.e. `in->asize` is
- * not zero), then it will be overwritten when applying the filters.  If
- * not, then it will be left untouched.
- *
- * If there are no filters to apply (or `filters` is NULL), then the `out`
- * buffer will reference the `in` buffer data (with `asize` set to zero)
- * instead of allocating data.  This keeps allocations to a minimum, but
- * it means you have to be careful about freeing the `in` data since `out`
- * may be pointing to it!
- *
  * @param out Buffer to store the result of the filtering
  * @param filters A loaded git_filter_list (or NULL)
  * @param in Buffer containing the data to filter
+ * @param in_len The length of the input buffer
  * @return 0 on success, an error code otherwise
  */
-GIT_EXTERN(int) git_filter_list_apply_to_data(
+GIT_EXTERN(int) git_filter_list_apply_to_buffer(
        git_buf *out,
        git_filter_list *filters,
-       git_buf *in);
+       const char *in,
+       size_t in_len);
 
 /**
  * Apply a filter list to the contents of a file on disk
@@ -175,12 +219,14 @@ GIT_EXTERN(int) git_filter_list_apply_to_blob(
  * Apply a filter list to an arbitrary buffer as a stream
  *
  * @param filters the list of filters to apply
- * @param data the buffer to filter
+ * @param buffer the buffer to filter
+ * @param len the size of the buffer
  * @param target the stream into which the data will be written
  */
-GIT_EXTERN(int) git_filter_list_stream_data(
+GIT_EXTERN(int) git_filter_list_stream_buffer(
        git_filter_list *filters,
-       git_buf *data,
+       const char *buffer,
+       size_t len,
        git_writestream *target);
 
 /**
index 213ae977757e537d59ae8a622ea9c5c90b80f343..712ae474a060b63a5b06ad80b627b60e6d6c22ce 100644 (file)
@@ -43,8 +43,9 @@ GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_reposi
  * Note that a commit is not considered a descendant of itself, in contrast
  * to `git merge-base --is-ancestor`.
  *
- * @param commit a previously loaded commit.
- * @param ancestor a potential ancestor commit.
+ * @param repo the repository where the commits exist
+ * @param commit a previously loaded commit
+ * @param ancestor a potential ancestor commit
  * @return 1 if the given commit is a descendant of the potential ancestor,
  * 0 if not, error code otherwise.
  */
@@ -53,6 +54,23 @@ GIT_EXTERN(int) git_graph_descendant_of(
        const git_oid *commit,
        const git_oid *ancestor);
 
+/**
+ * Determine if a commit is reachable from any of a list of commits by
+ * following parent edges.
+ *
+ * @param repo the repository where the commits exist
+ * @param commit a previously loaded commit
+ * @param length the number of commits in the provided `descendant_array`
+ * @param descendant_array oids of the commits
+ * @return 1 if the given commit is an ancestor of any of the given potential
+ * descendants, 0 if not, error code otherwise.
+ */
+GIT_EXTERN(int) git_graph_reachable_from_any(
+       git_repository *repo,
+       const git_oid *commit,
+       const git_oid descendant_array[],
+       size_t length);
+
 /** @} */
 GIT_END_DECL
 #endif
index 314135109ff95db48c089f946d7dd32515f78f61..532a52091f4c24b0dbbb04942e620a3c6a9e0137 100644 (file)
@@ -349,7 +349,7 @@ GIT_EXTERN(int) git_index_write_tree(git_oid *out, git_index *index);
  *
  * The index must not contain any file in conflict.
  *
- * @param out Pointer where to store OID of the the written tree
+ * @param out Pointer where to store OID of the written tree
  * @param index Index to write
  * @param repo Repository where to write the tree
  * @return 0 on success, GIT_EUNMERGED when the index is not clean
@@ -702,7 +702,7 @@ GIT_EXTERN(int) git_index_update_all(
  * @param at_pos the address to which the position of the index entry is written (optional)
  * @param index an existing index object
  * @param path path to search
- * @return a zero-based position in the index if found; GIT_ENOTFOUND otherwise
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path);
 
@@ -713,7 +713,7 @@ GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *pat
  * @param at_pos the address to which the position of the index entry is written (optional)
  * @param index an existing index object
  * @param prefix the prefix to search for
- * @return 0 with valid value in at_pos; an error code otherwise
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix);
 
index 8059e4db361a1672af6627e476aec86333165c62..a434d243f267102a771424d1769ecea75e73aec8 100644 (file)
@@ -51,7 +51,7 @@ typedef struct git_indexer_progress {
  * Type for progress callbacks during indexing.  Return a value less
  * than zero to cancel the indexing or download.
  *
- * @param stats Structure containing information about the state of the tran    sfer
+ * @param stats Structure containing information about the state of the transfer
  * @param payload Payload provided by caller
  */
 typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *stats, void *payload);
@@ -64,6 +64,7 @@ typedef struct git_indexer_options {
 
        /** progress_cb function to call with progress information */
        git_indexer_progress_cb progress_cb;
+
        /** progress_cb_payload payload for the progress callback */
        void *progress_cb_payload;
 
index c36149e5ba0f79406ed2d5c49262d50ac919d4fa..c135881a7c82673231823312e4fc1d8573ff1b3c 100644 (file)
@@ -84,8 +84,8 @@ GIT_EXTERN(void) git_note_iterator_free(git_note_iterator *it);
  *         (negative value)
  */
 GIT_EXTERN(int) git_note_next(
-       git_oidnote_id,
-       git_oidannotated_id,
+       git_oid *note_id,
+       git_oid *annotated_id,
        git_note_iterator *it);
 
 
index c4bfa5290b0e9a7e1ec779ab6c332d44a97ed0b3..dd484553ff24397ef519a20d21f4ec0e45c7cc58 100644 (file)
@@ -70,7 +70,7 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir);
  *
  * @param odb database to add the backend to
  * @param path path to the objects folder for the alternate
- * @return 0 on success; error code otherwise
+ * @return 0 on success, error code otherwise
  */
 GIT_EXTERN(int) git_odb_add_disk_alternate(git_odb *odb, const char *path);
 
@@ -94,9 +94,8 @@ GIT_EXTERN(void) git_odb_free(git_odb *db);
  * @param out pointer where to store the read object
  * @param db database to search for the object in.
  * @param id identity of the object to read.
- * @return
- * - 0 if the object was read;
- * - GIT_ENOTFOUND if the object is not in the database.
+ * @return 0 if the object was read, GIT_ENOTFOUND if the object is
+ *         not in the database.
  */
 GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id);
 
@@ -122,10 +121,9 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i
  * @param db database to search for the object in.
  * @param short_id a prefix of the id of the object to read.
  * @param len the length of the prefix
- * @return
- * - 0 if the object was read;
- * - GIT_ENOTFOUND if the object is not in the database.
- * - GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix)
+ * @return 0 if the object was read, GIT_ENOTFOUND if the object is not in the
+ *         database. GIT_EAMBIGUOUS if the prefix is ambiguous
+ *         (several objects match the prefix)
  */
 GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len);
 
@@ -143,9 +141,8 @@ GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git
  * @param type_out pointer where to store the type
  * @param db database to search for the object in.
  * @param id identity of the object to read.
- * @return
- * - 0 if the object was read;
- * - GIT_ENOTFOUND if the object is not in the database.
+ * @return 0 if the object was read, GIT_ENOTFOUND if the object is not
+ *         in the database.
  */
 GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_object_t *type_out, git_odb *db, const git_oid *id);
 
@@ -154,9 +151,7 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_object_t *type_out, git
  *
  * @param db database to be searched for the given object.
  * @param id the object to search for.
- * @return
- * - 1, if the object was found
- * - 0, otherwise
+ * @return 1 if the object was found, 0 otherwise
  */
 GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
 
@@ -305,7 +300,7 @@ GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, git_obje
  * @param stream the stream
  * @param buffer the data to write
  * @param len the buffer's length
- * @return 0 if the write succeeded; error code otherwise
+ * @return 0 if the write succeeded, error code otherwise
  */
 GIT_EXTERN(int) git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len);
 
@@ -320,7 +315,7 @@ GIT_EXTERN(int) git_odb_stream_write(git_odb_stream *stream, const char *buffer,
  *
  * @param out pointer to store the resulting object's id
  * @param stream the stream
- * @return 0 on success; an error code otherwise
+ * @return 0 on success, an error code otherwise
  */
 GIT_EXTERN(int) git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream);
 
@@ -362,7 +357,7 @@ GIT_EXTERN(void) git_odb_stream_free(git_odb_stream *stream);
  * @param type pointer where to store the type of the object
  * @param db object database where the stream will read from
  * @param oid oid of the object the stream will read from
- * @return 0 if the stream was created; error code otherwise
+ * @return 0 if the stream was created, error code otherwise
  */
 GIT_EXTERN(int) git_odb_open_rstream(
        git_odb_stream **out,
@@ -395,6 +390,20 @@ GIT_EXTERN(int) git_odb_write_pack(
        git_indexer_progress_cb progress_cb,
        void *progress_payload);
 
+/**
+ * Write a `multi-pack-index` file from all the `.pack` files in the ODB.
+ *
+ * If the ODB layer understands pack files, then this will create a file called
+ * `multi-pack-index` next to the `.pack` and `.idx` files, which will contain
+ * an index of all objects stored in `.pack` files. This will allow for
+ * O(log n) lookup for n objects (regardless of how many packfiles there
+ * exist).
+ *
+ * @param db object database where the `multi-pack-index` file will be written.
+ */
+GIT_EXTERN(int) git_odb_write_multi_pack_index(
+       git_odb *db);
+
 /**
  * Determine the object-ID (sha1 hash) of a data buffer
  *
@@ -501,7 +510,7 @@ GIT_EXTERN(git_object_t) git_odb_object_type(git_odb_object *object);
  * @param odb database to add the backend to
  * @param backend pointer to a git_odb_backend instance
  * @param priority Value for ordering the backends queue
- * @return 0 on success; error code otherwise
+ * @return 0 on success, error code otherwise
  */
 GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority);
 
@@ -522,7 +531,7 @@ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int
  * @param odb database to add the backend to
  * @param backend pointer to a git_odb_backend instance
  * @param priority Value for ordering the backends queue
- * @return 0 on success; error code otherwise
+ * @return 0 on success, error code otherwise
  */
 GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority);
 
@@ -540,10 +549,25 @@ GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb);
  * @param out output pointer to ODB backend at pos
  * @param odb object database
  * @param pos index into object database backend list
- * @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0
+ * @return 0 on success, GIT_ENOTFOUND if pos is invalid, other errors < 0
  */
 GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos);
 
+/**
+ * Set the git commit-graph for the ODB.
+ *
+ * After a successfull call, the ownership of the cgraph parameter will be
+ * transferred to libgit2, and the caller should not free it.
+ *
+ * The commit-graph can also be unset by explicitly passing NULL as the cgraph
+ * parameter.
+ *
+ * @param odb object database
+ * @param cgraph the git commit-graph
+ * @return 0 on success; error code otherwise
+ */
+GIT_EXTERN(int) git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph);
+
 /** @} */
 GIT_END_DECL
 #endif
index 0b320459787e429a6b066bf90fd66b462605d0aa..94fc58daba46c6467f15f96324fbc4553a55977b 100644 (file)
@@ -19,19 +19,16 @@ typedef struct git_oidarray {
 } git_oidarray;
 
 /**
- * Free the OID array
- *
- * This method must (and must only) be called on `git_oidarray`
- * objects where the array is allocated by the library. Not doing so,
- * will result in a memory leak.
+ * Free the object IDs contained in an oid_array.  This method should
+ * be called on `git_oidarray` objects that were provided by the
+ * library.  Not doing so will result in a memory leak.
  *
  * This does not free the `git_oidarray` itself, since the library will
- * never allocate that object directly itself (it is more commonly embedded
- * inside another struct or created on the stack).
+ * never allocate that object directly itself.
  *
  * @param array git_oidarray from which to free oid data
  */
-GIT_EXTERN(void) git_oidarray_free(git_oidarray *array);
+GIT_EXTERN(void) git_oidarray_dispose(git_oidarray *array);
 
 /** @} */
 GIT_END_DECL
index b177798e6a576e148edd08525ec770524d7f9e8c..fde9659e713aa969e175284b511bce4bd92a8621 100644 (file)
@@ -28,6 +28,14 @@ GIT_BEGIN_DECL
  */
 typedef struct git_patch git_patch;
 
+/**
+ * Get the repository associated with this patch. May be NULL.
+ *
+ * @param patch the patch
+ * @return a pointer to the repository
+ */
+GIT_EXTERN(git_repository *) git_patch_owner(const git_patch *patch);
+
 /**
  * Return a patch for an entry in the diff list.
  *
index 99a02fef9f159ae0af431c76d6db02e4c17892e6..11e452cbf01159d099d325b4469033b539932768 100644 (file)
@@ -74,14 +74,38 @@ typedef struct {
         */
        git_checkout_options checkout_options;
 
+       /**
+        * Optional callback that allows users to override commit
+        * creation in `git_rebase_commit`.  If specified, users can
+        * create their own commit and provide the commit ID, which
+        * may be useful for signing commits or otherwise customizing
+        * the commit creation.
+        *
+        * If this callback returns `GIT_PASSTHROUGH`, then
+        * `git_rebase_commit` will continue to create the commit.
+        */
+       git_commit_create_cb commit_create_cb;
+
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
        /**
         * If provided, this will be called with the commit content, allowing
         * a signature to be added to the rebase commit. Can be skipped with
         * GIT_PASSTHROUGH. If GIT_PASSTHROUGH is returned, a commit will be made
         * without a signature.
+        *
         * This field is only used when performing git_rebase_commit.
+        *
+        * This callback is not invoked if a `git_commit_create_cb` is
+        * specified.
+        *
+        * This callback is deprecated; users should provide a
+        * creation callback as `commit_create_cb` that produces a
+        * commit buffer, signs it, and commits it.
         */
-       git_commit_signing_cb signing_cb;
+       int (*signing_cb)(git_buf *, git_buf *, const char *, void *);
+#endif
 
        /**
         * This will be passed to each of the callbacks in this struct
index c9cce221248b5876f1a4b28afc2bee5ded616185..7ebb209b29196dbabbd7a5c013561eb8dc342495 100644 (file)
@@ -97,6 +97,9 @@ GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, co
  * of updating does not match the one passed through `current_value`
  * (i.e. if the ref has changed since the user read it).
  *
+ * If `current_value` is all zeros, this function will return GIT_EMODIFIED
+ * if the ref already exists.
+ *
  * @param out Pointer to the newly created reference
  * @param repo Repository where that reference will live
  * @param name The name of the reference
@@ -169,7 +172,7 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor
  *
  * The message for the reflog will be ignored if the reference does
  * not belong in the standard set (HEAD, branches and remote-tracking
- * branches) and and it does not have a reflog.
+ * branches) and it does not have a reflog.
  *
  * @param out Pointer to the newly created reference
  * @param repo Repository where that reference will live
@@ -206,7 +209,7 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo,
  *
  * The message for the reflog will be ignored if the reference does
  * not belong in the standard set (HEAD, branches and remote-tracking
- * branches) and and it does not have a reflog.
+ * branches) and it does not have a reflog.
  *
  * It will return GIT_EMODIFIED if the reference's value at the time
  * of updating does not match the one passed through `current_id`
@@ -318,7 +321,7 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref);
  *
  * The message for the reflog will be ignored if the reference does
  * not belong in the standard set (HEAD, branches and remote-tracking
- * branches) and and it does not have a reflog.
+ * branches) and it does not have a reflog.
  *
  * @param out Pointer to the newly created reference
  * @param ref The reference
@@ -743,10 +746,11 @@ GIT_EXTERN(int) git_reference_peel(
  *    the characters '~', '^', ':', '\\', '?', '[', and '*', and the
  *    sequences ".." and "@{" which have special meaning to revparse.
  *
+ * @param valid output pointer to set with validity of given reference name
  * @param refname name to be checked.
- * @return 1 if the reference name is acceptable; 0 if it isn't
+ * @return 0 on success or an error code
  */
-GIT_EXTERN(int) git_reference_is_valid_name(const char *refname);
+GIT_EXTERN(int) git_reference_name_is_valid(int *valid, const char *refname);
 
 /**
  * Get the reference's short name
index 51d9c723596ca1a51562795c5ec090de50f144b1..4d57eaaf74f96713c64c193e3fb0dc3e528320ba 100644 (file)
@@ -212,7 +212,8 @@ GIT_EXTERN(const char *) git_remote_name(const git_remote *remote);
  * Get the remote's url
  *
  * If url.*.insteadOf has been configured for this URL, it will
- * return the modified URL.
+ * return the modified URL.  If `git_remote_set_instance_pushurl`
+ * has been called for this remote, then that URL will be returned.
  *
  * @param remote the remote
  * @return a pointer to the url
@@ -220,10 +221,11 @@ GIT_EXTERN(const char *) git_remote_name(const git_remote *remote);
 GIT_EXTERN(const char *) git_remote_url(const git_remote *remote);
 
 /**
- * Get the remote's url for pushing
+ * Get the remote's url for pushing.
  *
  * If url.*.pushInsteadOf has been configured for this URL, it
- * will return the modified URL.
+ * will return the modified URL.  If `git_remote_set_instance_pushurl`
+ * has been called for this remote, then that URL will be returned.
  *
  * @param remote the remote
  * @return a pointer to the url or NULL if no special url for pushing is set
@@ -241,7 +243,7 @@ GIT_EXTERN(const char *) git_remote_pushurl(const git_remote *remote);
  * @param url the url to set
  * @return 0 or an error value
  */
-GIT_EXTERN(int) git_remote_set_url(git_repository *repo, const char *remote, const charurl);
+GIT_EXTERN(int) git_remote_set_url(git_repository *repo, const char *remote, const char *url);
 
 /**
  * Set the remote's url for pushing in the configuration.
@@ -253,8 +255,29 @@ GIT_EXTERN(int) git_remote_set_url(git_repository *repo, const char *remote, con
  * @param repo the repository in which to perform the change
  * @param remote the remote's name
  * @param url the url to set
+ * @return 0, or an error code
  */
-GIT_EXTERN(int) git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url);
+GIT_EXTERN(int) git_remote_set_pushurl(git_repository *repo, const char *remote, const char *url);
+
+/**
+ * Set the url for this particular url instance.  The URL in the
+ * configuration will be ignored, and will not be changed.
+ *
+ * @param remote the remote's name
+ * @param url the url to set
+ * @return 0 or an error value
+ */
+GIT_EXTERN(int) git_remote_set_instance_url(git_remote *remote, const char *url);
+
+/**
+ * Set the push url for this particular url instance.  The URL in the
+ * configuration will be ignored, and will not be changed.
+ *
+ * @param remote the remote's name
+ * @param url the url to set
+ * @return 0 or an error value
+ */
+GIT_EXTERN(int) git_remote_set_instance_pushurl(git_remote *remote, const char *url);
 
 /**
  * Add a fetch refspec to the remote's configuration
@@ -428,7 +451,7 @@ typedef int GIT_CALLBACK(git_push_transfer_progress_cb)(
        unsigned int current,
        unsigned int total,
        size_t bytes,
-       voidpayload);
+       void *payload);
 
 /**
  * Represents an update which will be performed on the remote during push
@@ -476,6 +499,7 @@ typedef int GIT_CALLBACK(git_push_negotiation)(const git_push_update **updates,
  */
 typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, const char *status, void *data);
 
+#ifndef GIT_DEPRECATE_HARD
 /**
  * Callback to resolve URLs before connecting to remote
  *
@@ -487,8 +511,22 @@ typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, cons
  * @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
  * @param payload Payload provided by the caller
  * @return 0 on success, GIT_PASSTHROUGH or an error
+ * @deprecated Use `git_remote_set_instance_url`
  */
 typedef int GIT_CALLBACK(git_url_resolve_cb)(git_buf *url_resolved, const char *url, int direction, void *payload);
+#endif
+
+/**
+ * Callback invoked immediately before we attempt to connect to the
+ * given url.  Callers may change the URL before the connection by
+ * calling `git_remote_set_instance_url` in the callback.
+ *
+ * @param remote The remote to be connected
+ * @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
+ * @param payload Payload provided by the caller
+ * @return 0 on success, or an error
+ */
+typedef int GIT_CALLBACK(git_remote_ready_cb)(git_remote *remote, int direction, void *payload);
 
 /**
  * The callback settings structure
@@ -574,17 +612,29 @@ struct git_remote_callbacks {
         */
        git_transport_cb transport;
 
+       /**
+        * Callback when the remote is ready to connect.
+        */
+       git_remote_ready_cb remote_ready;
+
        /**
         * This will be passed to each of the callbacks in this struct
         * as the last parameter.
         */
        void *payload;
 
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
        /**
         * Resolve URL before connecting to remote.
         * The returned URL will be used to connect to the remote instead.
+        *
+        * This callback is deprecated; users should use
+        * git_remote_ready_cb and configure the instance URL instead.
         */
        git_url_resolve_cb resolve_url;
+#endif
 };
 
 #define GIT_REMOTE_CALLBACKS_VERSION 1
@@ -876,8 +926,10 @@ GIT_EXTERN(git_remote_autotag_option_t) git_remote_autotag(const git_remote *rem
  * @param repo the repository in which to make the change
  * @param remote the name of the remote
  * @param value the new value to take.
+ * @return 0, or an error code.
  */
 GIT_EXTERN(int) git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value);
+
 /**
  * Retrieve the ref-prune setting
  *
@@ -915,10 +967,11 @@ GIT_EXTERN(int) git_remote_rename(
 /**
  * Ensure the remote name is well-formed.
  *
+ * @param valid output pointer to set with validity of given remote name
  * @param remote_name name to be checked.
- * @return 1 if the reference name is acceptable; 0 if it isn't
+ * @return 0 on success or an error code
  */
-GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
+GIT_EXTERN(int) git_remote_name_is_valid(int *valid, const char *remote_name);
 
 /**
 * Delete an existing persisted remote.
@@ -943,7 +996,7 @@ GIT_EXTERN(int) git_remote_delete(git_repository *repo, const char *name);
  *
  * This function must only be called after connecting.
  *
- * @param out the buffern in which to store the reference name
+ * @param out the buffer in which to store the reference name
  * @param remote the remote
  * @return 0, GIT_ENOTFOUND if the remote does not have any references
  * or none of them point to HEAD's commit, or an error message.
index 9ddcd340420f008ff3c8229e12e0609b13206e61..8d1cffc9bf62fe7ee733a8707b8ccb2a68015a7b 100644 (file)
@@ -219,36 +219,54 @@ GIT_EXTERN(int) git_repository_init(
  *
  * These flags configure extra behaviors to `git_repository_init_ext`.
  * In every case, the default behavior is the zero value (i.e. flag is
- * not set).  Just OR the flag values together for the `flags` parameter
- * when initializing a new repo.  Details of individual values are:
- *
- * * BARE   - Create a bare repository with no working directory.
- * * NO_REINIT - Return an GIT_EEXISTS error if the repo_path appears to
- *        already be an git repository.
- * * NO_DOTGIT_DIR - Normally a "/.git/" will be appended to the repo
- *        path for non-bare repos (if it is not already there), but
- *        passing this flag prevents that behavior.
- * * MKDIR  - Make the repo_path (and workdir_path) as needed.  Init is
- *        always willing to create the ".git" directory even without this
- *        flag.  This flag tells init to create the trailing component of
- *        the repo and workdir paths as needed.
- * * MKPATH - Recursively make all components of the repo and workdir
- *        paths as necessary.
- * * EXTERNAL_TEMPLATE - libgit2 normally uses internal templates to
- *        initialize a new repo.  This flags enables external templates,
- *        looking the "template_path" from the options if set, or the
- *        `init.templatedir` global config if not, or falling back on
- *        "/usr/share/git-core/templates" if it exists.
- * * GIT_REPOSITORY_INIT_RELATIVE_GITLINK - If an alternate workdir is
- *        specified, use relative paths for the gitdir and core.worktree.
+ * not set). Just OR the flag values together for the `flags` parameter
+ * when initializing a new repo.
  */
 typedef enum {
+       /**
+        * Create a bare repository with no working directory.
+        */
        GIT_REPOSITORY_INIT_BARE              = (1u << 0),
+
+       /**
+        * Return an GIT_EEXISTS error if the repo_path appears to already be
+        * an git repository.
+        */
        GIT_REPOSITORY_INIT_NO_REINIT         = (1u << 1),
+
+       /**
+        * Normally a "/.git/" will be appended to the repo path for
+        * non-bare repos (if it is not already there), but passing this flag
+        * prevents that behavior.
+        */
        GIT_REPOSITORY_INIT_NO_DOTGIT_DIR     = (1u << 2),
+
+       /**
+        * Make the repo_path (and workdir_path) as needed. Init is always willing
+        * to create the ".git" directory even without this flag. This flag tells
+        * init to create the trailing component of the repo and workdir paths
+        * as needed.
+        */
        GIT_REPOSITORY_INIT_MKDIR             = (1u << 3),
+
+       /**
+        * Recursively make all components of the repo and workdir paths as
+        * necessary.
+        */
        GIT_REPOSITORY_INIT_MKPATH            = (1u << 4),
+
+       /**
+        * libgit2 normally uses internal templates to initialize a new repo.
+        * This flags enables external templates, looking the "template_path" from
+        * the options if set, or the `init.templatedir` global config if not,
+        * or falling back on "/usr/share/git-core/templates" if it exists.
+        */
        GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = (1u << 5),
+
+       /**
+        * If an alternate workdir is specified, use relative paths for the gitdir
+        * and core.worktree.
+        */
        GIT_REPOSITORY_INIT_RELATIVE_GITLINK  = (1u << 6),
 } git_repository_init_flag_t;
 
@@ -257,17 +275,23 @@ typedef enum {
  *
  * Set the mode field of the `git_repository_init_options` structure
  * either to the custom mode that you would like, or to one of the
- * following modes:
- *
- * * SHARED_UMASK - Use permissions configured by umask - the default.
- * * SHARED_GROUP - Use "--shared=group" behavior, chmod'ing the new repo
- *        to be group writable and "g+sx" for sticky group assignment.
- * * SHARED_ALL - Use "--shared=all" behavior, adding world readability.
- * * Anything else - Set to custom value.
+ * defined modes.
  */
 typedef enum {
+       /**
+        * Use permissions configured by umask - the default.
+        */
        GIT_REPOSITORY_INIT_SHARED_UMASK = 0,
+
+       /**
+        * Use "--shared=group" behavior, chmod'ing the new repo to be group
+        * writable and "g+sx" for sticky group assignment.
+        */
        GIT_REPOSITORY_INIT_SHARED_GROUP = 0002775,
+
+       /**
+        * Use "--shared=all" behavior, adding world readability.
+        */
        GIT_REPOSITORY_INIT_SHARED_ALL   = 0002777,
 } git_repository_init_mode_t;
 
@@ -275,38 +299,57 @@ typedef enum {
  * Extended options structure for `git_repository_init_ext`.
  *
  * This contains extra options for `git_repository_init_ext` that enable
- * additional initialization features.  The fields are:
- *
- * * flags - Combination of GIT_REPOSITORY_INIT flags above.
- * * mode  - Set to one of the standard GIT_REPOSITORY_INIT_SHARED_...
- *        constants above, or to a custom value that you would like.
- * * workdir_path - The path to the working dir or NULL for default (i.e.
- *        repo_path parent on non-bare repos).  IF THIS IS RELATIVE PATH,
- *        IT WILL BE EVALUATED RELATIVE TO THE REPO_PATH.  If this is not
- *        the "natural" working directory, a .git gitlink file will be
- *        created here linking to the repo_path.
- * * description - If set, this will be used to initialize the "description"
- *        file in the repository, instead of using the template content.
- * * template_path - When GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE is set,
- *        this contains the path to use for the template directory.  If
- *        this is NULL, the config or default directory options will be
- *        used instead.
- * * initial_head - The name of the head to point HEAD at.  If NULL, then
- *        this will be treated as "master" and the HEAD ref will be set
- *        to "refs/heads/master".  If this begins with "refs/" it will be
- *        used verbatim; otherwise "refs/heads/" will be prefixed.
- * * origin_url - If this is non-NULL, then after the rest of the
- *        repository initialization is completed, an "origin" remote
- *        will be added pointing to this URL.
+ * additional initialization features.
  */
 typedef struct {
        unsigned int version;
+
+       /**
+        * Combination of GIT_REPOSITORY_INIT flags above.
+        */
        uint32_t    flags;
+
+       /**
+        * Set to one of the standard GIT_REPOSITORY_INIT_SHARED_... constants
+        * above, or to a custom value that you would like.
+        */
        uint32_t    mode;
+
+       /**
+        * The path to the working dir or NULL for default (i.e. repo_path parent
+        * on non-bare repos). IF THIS IS RELATIVE PATH, IT WILL BE EVALUATED
+        * RELATIVE TO THE REPO_PATH. If this is not the "natural" working
+        * directory, a .git gitlink file will be created here linking to the
+        * repo_path.
+        */
        const char *workdir_path;
+
+       /**
+        * If set, this will be used to initialize the "description" file in the
+        * repository, instead of using the template content.
+        */
        const char *description;
+
+       /**
+        * When GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE is set, this contains
+        * the path to use for the template directory. If this is NULL, the config
+        * or default directory options will be used instead.
+        */
        const char *template_path;
+
+       /**
+        * The name of the head to point HEAD at. If NULL, then this will be
+        * treated as "master" and the HEAD ref will be set to "refs/heads/master".
+        * If this begins with "refs/" it will be used verbatim;
+        * otherwise "refs/heads/" will be prefixed.
+        */
        const char *initial_head;
+
+       /**
+        * If this is non-NULL, then after the rest of the repository
+        * initialization is completed, an "origin" remote will be added
+        * pointing to this URL.
+        */
        const char *origin_url;
 } git_repository_init_options;
 
@@ -719,13 +762,15 @@ GIT_EXTERN(int) git_repository_mergehead_foreach(
  *
  * @param out Output value of calculated SHA
  * @param repo Repository pointer
- * @param path Path to file on disk whose contents should be hashed. If the
- *             repository is not NULL, this can be a relative path.
+ * @param path Path to file on disk whose contents should be hashed.  This
+ *             may be an absolute path or a relative path, in which case it
+ *             will be treated as a path within the working directory.
  * @param type The object type to hash as (e.g. GIT_OBJECT_BLOB)
  * @param as_path The path to use to look up filtering rules. If this is
- *             NULL, then the `path` parameter will be used instead. If
- *             this is passed as the empty string, then no filters will be
- *             applied when calculating the hash.
+ *             an empty string then no filters will be applied when
+ *             calculating the hash. If this is `NULL` and the `path`
+ *             parameter is a file within the repository's working
+ *             directory, then the `path` will be used.
  * @return 0 on success, or an error code
  */
 GIT_EXTERN(int) git_repository_hashfile(
@@ -754,8 +799,8 @@ GIT_EXTERN(int) git_repository_hashfile(
  * @return 0 on success, or an error code
  */
 GIT_EXTERN(int) git_repository_set_head(
-       git_repositoryrepo,
-       const charrefname);
+       git_repository *repo,
+       const char *refname);
 
 /**
  * Make the repository HEAD directly point to the Commit.
@@ -774,8 +819,8 @@ GIT_EXTERN(int) git_repository_set_head(
  * @return 0 on success, or an error code
  */
 GIT_EXTERN(int) git_repository_set_head_detached(
-       git_repositoryrepo,
-       const git_oidcommitish);
+       git_repository *repo,
+       const git_oid *commitish);
 
 /**
  * Make the repository HEAD directly point to the Commit.
@@ -811,7 +856,7 @@ GIT_EXTERN(int) git_repository_set_head_detached_from_annotated(
  * branch or an error code
  */
 GIT_EXTERN(int) git_repository_detach_head(
-       git_repositoryrepo);
+       git_repository *repo);
 
 /**
  * Repository state
index d170e1621842bb20494e59eef402027c7dd552e6..e14ddee96cf27aa9312ffde89d473228f70b3d7c 100644 (file)
@@ -70,12 +70,12 @@ GIT_EXTERN(int) git_revparse_ext(
  */
 typedef enum {
        /** The spec targeted a single object. */
-       GIT_REVPARSE_SINGLE         = 1 << 0,
+       GIT_REVSPEC_SINGLE         = 1 << 0,
        /** The spec targeted a range of commits. */
-       GIT_REVPARSE_RANGE          = 1 << 1,
+       GIT_REVSPEC_RANGE          = 1 << 1,
        /** The spec used the '...' operator, which invokes special semantics. */
-       GIT_REVPARSE_MERGE_BASE     = 1 << 2,
-} git_revparse_mode_t;
+       GIT_REVSPEC_MERGE_BASE     = 1 << 2,
+} git_revspec_t;
 
 /**
  * Git Revision Spec: output of a `git_revparse` operation
@@ -85,7 +85,7 @@ typedef struct {
        git_object *from;
        /** The right element of the revspec; must be freed by the user */
        git_object *to;
-       /** The intent of the revspec (i.e. `git_revparse_mode_t` flags) */
+       /** The intent of the revspec (i.e. `git_revspec_mode_t` flags) */
        unsigned int flags;
 } git_revspec;
 
index 625e51b4b4fdc305c9186afcb3d20f634fbd5651..795920ebc767aec4267d2fc35975ab21c1163809 100644 (file)
@@ -200,7 +200,7 @@ GIT_EXTERN(int) git_stash_apply(
  */
 typedef int GIT_CALLBACK(git_stash_cb)(
        size_t index,
-       const charmessage,
+       const char *message,
        const git_oid *stash_id,
        void *payload);
 
index 9693cc47862eb307af12321554a549465f87845f..543e3faa8f7c64472c3b140a10bffb15ca702a44 100644 (file)
@@ -69,89 +69,141 @@ typedef int GIT_CALLBACK(git_status_cb)(
  * With `git_status_foreach_ext`, this will control which changes get
  * callbacks.  With `git_status_list_new`, these will control which
  * changes are included in the list.
- *
- * - GIT_STATUS_SHOW_INDEX_AND_WORKDIR is the default.  This roughly
- *   matches `git status --porcelain` regarding which files are
- *   included and in what order.
- * - GIT_STATUS_SHOW_INDEX_ONLY only gives status based on HEAD to index
- *   comparison, not looking at working directory changes.
- * - GIT_STATUS_SHOW_WORKDIR_ONLY only gives status based on index to
- *   working directory comparison, not comparing the index to the HEAD.
  */
 typedef enum {
+       /**
+        * The default. This roughly matches `git status --porcelain` regarding
+        * which files are included and in what order.
+        */
        GIT_STATUS_SHOW_INDEX_AND_WORKDIR = 0,
+
+       /**
+        * Only gives status based on HEAD to index comparison, not looking at
+        * working directory changes.
+        */
        GIT_STATUS_SHOW_INDEX_ONLY = 1,
+
+       /**
+        * Only gives status based on index to working directory comparison,
+        * not comparing the index to the HEAD.
+        */
        GIT_STATUS_SHOW_WORKDIR_ONLY = 2,
 } git_status_show_t;
 
 /**
  * Flags to control status callbacks
  *
- * - GIT_STATUS_OPT_INCLUDE_UNTRACKED says that callbacks should be made
- *   on untracked files.  These will only be made if the workdir files are
- *   included in the status "show" option.
- * - GIT_STATUS_OPT_INCLUDE_IGNORED says that ignored files get callbacks.
- *   Again, these callbacks will only be made if the workdir files are
- *   included in the status "show" option.
- * - GIT_STATUS_OPT_INCLUDE_UNMODIFIED indicates that callback should be
- *   made even on unmodified files.
- * - GIT_STATUS_OPT_EXCLUDE_SUBMODULES indicates that submodules should be
- *   skipped.  This only applies if there are no pending typechanges to
- *   the submodule (either from or to another type).
- * - GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS indicates that all files in
- *   untracked directories should be included.  Normally if an entire
- *   directory is new, then just the top-level directory is included (with
- *   a trailing slash on the entry name).  This flag says to include all
- *   of the individual files in the directory instead.
- * - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given path
- *   should be treated as a literal path, and not as a pathspec pattern.
- * - GIT_STATUS_OPT_RECURSE_IGNORED_DIRS indicates that the contents of
- *   ignored directories should be included in the status.  This is like
- *   doing `git ls-files -o -i --exclude-standard` with core git.
- * - GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX indicates that rename detection
- *   should be processed between the head and the index and enables
- *   the GIT_STATUS_INDEX_RENAMED as a possible status flag.
- * - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates that rename
- *   detection should be run between the index and the working directory
- *   and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
- * - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
- *   sensitivity for the file system and forces the output to be in
- *   case-sensitive order
- * - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
- *   sensitivity for the file system and forces the output to be in
- *   case-insensitive order
- * - GIT_STATUS_OPT_RENAMES_FROM_REWRITES indicates that rename detection
- *   should include rewritten files
- * - GIT_STATUS_OPT_NO_REFRESH bypasses the default status behavior of
- *   doing a "soft" index reload (i.e. reloading the index data if the
- *   file on disk has been modified outside libgit2).
- * - GIT_STATUS_OPT_UPDATE_INDEX tells libgit2 to refresh the stat cache
- *   in the index for files that are unchanged but have out of date stat
- *   information in the index.  It will result in less work being done on
- *   subsequent calls to get status.  This is mutually exclusive with the
- *   NO_REFRESH option.
- *
  * Calling `git_status_foreach()` is like calling the extended version
  * with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
  * and GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS.  Those options are bundled
  * together as `GIT_STATUS_OPT_DEFAULTS` if you want them as a baseline.
  */
 typedef enum {
+       /**
+        * Says that callbacks should be made on untracked files.
+        * These will only be made if the workdir files are included in the status
+        * "show" option.
+        */
        GIT_STATUS_OPT_INCLUDE_UNTRACKED                = (1u << 0),
+
+       /**
+        * Says that ignored files get callbacks.
+        * Again, these callbacks will only be made if the workdir files are
+        * included in the status "show" option.
+        */
        GIT_STATUS_OPT_INCLUDE_IGNORED                  = (1u << 1),
+
+       /**
+        * Indicates that callback should be made even on unmodified files.
+        */
        GIT_STATUS_OPT_INCLUDE_UNMODIFIED               = (1u << 2),
+
+       /**
+        * Indicates that submodules should be skipped.
+        * This only applies if there are no pending typechanges to the submodule
+        * (either from or to another type).
+        */
        GIT_STATUS_OPT_EXCLUDE_SUBMODULES               = (1u << 3),
+
+       /**
+        * Indicates that all files in untracked directories should be included.
+        * Normally if an entire directory is new, then just the top-level
+        * directory is included (with a trailing slash on the entry name).
+        * This flag says to include all of the individual files in the directory
+        * instead.
+        */
        GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS           = (1u << 4),
+
+       /**
+        * Indicates that the given path should be treated as a literal path,
+        * and not as a pathspec pattern.
+        */
        GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH           = (1u << 5),
+
+       /**
+        * Indicates that the contents of ignored directories should be included
+        * in the status. This is like doing `git ls-files -o -i --exclude-standard`
+        * with core git.
+        */
        GIT_STATUS_OPT_RECURSE_IGNORED_DIRS             = (1u << 6),
+
+       /**
+        * Indicates that rename detection should be processed between the head and
+        * the index and enables the GIT_STATUS_INDEX_RENAMED as a possible status
+        * flag.
+        */
        GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX            = (1u << 7),
+
+       /**
+        * Indicates that rename detection should be run between the index and the
+        * working directory and enabled GIT_STATUS_WT_RENAMED as a possible status
+        * flag.
+        */
        GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR         = (1u << 8),
+
+       /**
+        * Overrides the native case sensitivity for the file system and forces
+        * the output to be in case-sensitive order.
+        */
        GIT_STATUS_OPT_SORT_CASE_SENSITIVELY            = (1u << 9),
+
+       /**
+        * Overrides the native case sensitivity for the file system and forces
+        * the output to be in case-insensitive order.
+        */
        GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY          = (1u << 10),
+
+       /**
+        * Iindicates that rename detection should include rewritten files.
+        */
        GIT_STATUS_OPT_RENAMES_FROM_REWRITES            = (1u << 11),
+
+       /**
+        * Bypasses the default status behavior of doing a "soft" index reload
+        * (i.e. reloading the index data if the file on disk has been modified
+        * outside libgit2).
+        */
        GIT_STATUS_OPT_NO_REFRESH                       = (1u << 12),
+
+       /**
+        * Tells libgit2 to refresh the stat cache in the index for files that are
+        * unchanged but have out of date stat einformation in the index.
+        * It will result in less work being done on subsequent calls to get status.
+        * This is mutually exclusive with the NO_REFRESH option.
+        */
        GIT_STATUS_OPT_UPDATE_INDEX                     = (1u << 13),
+
+       /**
+        * Normally files that cannot be opened or read are ignored as
+        * these are often transient files; this option will return
+        * unreadable files as `GIT_STATUS_WT_UNREADABLE`.
+        */
        GIT_STATUS_OPT_INCLUDE_UNREADABLE               = (1u << 14),
+
+       /**
+        * Unreadable files will be detected and given the status
+        * untracked instead of unreadable.
+        */
        GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED  = (1u << 15),
 } git_status_opt_t;
 
@@ -168,7 +220,10 @@ typedef enum {
  *
  */
 typedef struct {
-       unsigned int      version; /**< The version */
+       /**
+        * The struct version; pass `GIT_STATUS_OPTIONS_VERSION`.
+        */
+       unsigned int version;
 
        /**
         * The `show` value is one of the `git_status_show_t` constants that
@@ -177,21 +232,22 @@ typedef struct {
        git_status_show_t show;
 
        /**
-        * The `flags` value is an OR'ed combination of the `git_status_opt_t`
-        * values above.
+        * The `flags` value is an OR'ed combination of the
+        * `git_status_opt_t` values above.
         */
        unsigned int      flags;
 
        /**
         * The `pathspec` is an array of path patterns to match (using
-        * fnmatch-style matching), or just an array of paths to match exactly if
-        * `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags.
+        * fnmatch-style matching), or just an array of paths to match
+        * exactly if `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified
+        * in the flags.
         */
        git_strarray      pathspec;
 
        /**
-        * The `baseline` is the tree to be used for comparison to the working directory
-        * and index; defaults to HEAD.
+        * The `baseline` is the tree to be used for comparison to the
+        * working directory and index; defaults to HEAD.
         */
        git_tree          *baseline;
 } git_status_options;
index c66fbb817c0d16f47edbb8e2adf0d78c3313ce8a..6950427d2d0219a7daa417c72e3972f3e4fbd8a4 100644 (file)
@@ -29,9 +29,7 @@
 //
 ///////////////////////////////////////////////////////////////////////////////
 
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
+#ifdef _MSC_VER // [
 
 #ifndef _MSC_STDINT_H_ // [
 #define _MSC_STDINT_H_
@@ -245,3 +243,5 @@ typedef uint64_t  uintmax_t;
 
 
 #endif // _MSC_STDINT_H_ ]
+
+#endif // _MSC_VER ]
\ No newline at end of file
index bedd76d6a86b765751529db7fe0014953bdf3b75..29d8bc1ce556942f5f3f3fd4dcc791f74b286ff7 100644 (file)
@@ -223,6 +223,15 @@ GIT_EXTERN(int) git_submodule_lookup(
        git_repository *repo,
        const char *name);
 
+/**
+ * Create an in-memory copy of a submodule. The copy must be explicitly
+ * free'd or it will leak.
+ *
+ * @param out Pointer to store the copy of the submodule.
+ * @param source Original submodule to copy.
+ */
+GIT_EXTERN(int) git_submodule_dup(git_submodule **out, git_submodule *source);
+
 /**
  * Release a submodule
  *
diff --git a/include/git2/sys/commit_graph.h b/include/git2/sys/commit_graph.h
new file mode 100644 (file)
index 0000000..f6c0fc4
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_commit_graph_h__
+#define INCLUDE_sys_git_commit_graph_h__
+
+#include "git2/common.h"
+#include "git2/types.h"
+
+/**
+ * @file git2/sys/commit_graph.h
+ * @brief Git commit-graph
+ * @defgroup git_commit_graph Git commit-graph APIs
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Opens a `git_commit_graph` from a path to an objects directory.
+ *
+ * This finds, opens, and validates the `commit-graph` file.
+ *
+ * @param cgraph_out the `git_commit_graph` struct to initialize.
+ * @param objects_dir the path to a git objects directory.
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir);
+
+/**
+ * Frees commit-graph data. This should only be called when memory allocated
+ * using `git_commit_graph_open` is not returned to libgit2 because it was not
+ * associated with the ODB through a successful call to
+ * `git_odb_set_commit_graph`.
+ *
+ * @param cgraph the commit-graph object to free. If NULL, no action is taken.
+ */
+GIT_EXTERN(void) git_commit_graph_free(git_commit_graph *cgraph);
+
+/**
+ * Create a new writer for `commit-graph` files.
+ *
+ * @param out Location to store the writer pointer.
+ * @param objects_info_dir The `objects/info` directory.
+ * The `commit-graph` file will be written in this directory.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_commit_graph_writer_new(
+               git_commit_graph_writer **out,
+               const char *objects_info_dir);
+
+/**
+ * Free the commit-graph writer and its resources.
+ *
+ * @param w The writer to free. If NULL no action is taken.
+ */
+GIT_EXTERN(void) git_commit_graph_writer_free(git_commit_graph_writer *w);
+
+/**
+ * Add an `.idx` file (associated to a packfile) to the writer.
+ *
+ * @param w The writer.
+ * @param repo The repository that owns the `.idx` file.
+ * @param idx_path The path of an `.idx` file.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_commit_graph_writer_add_index_file(
+               git_commit_graph_writer *w,
+               git_repository *repo,
+               const char *idx_path);
+
+/**
+ * Add a revwalk to the writer. This will add all the commits from the revwalk
+ * to the commit-graph.
+ *
+ * @param w The writer.
+ * @param walk The git_revwalk.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_commit_graph_writer_add_revwalk(
+               git_commit_graph_writer *w,
+               git_revwalk *walk);
+
+
+/**
+ * The strategy to use when adding a new set of commits to a pre-existing
+ * commit-graph chain.
+ */
+typedef enum {
+       /**
+        * Do not split commit-graph files. The other split strategy-related option
+        * fields are ignored.
+        */
+       GIT_COMMIT_GRAPH_SPLIT_STRATEGY_SINGLE_FILE = 0,
+} git_commit_graph_split_strategy_t;
+
+/**
+ * Options structure for
+ * `git_commit_graph_writer_commit`/`git_commit_graph_writer_dump`.
+ *
+ * Initialize with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`. Alternatively, you
+ * can use `git_commit_graph_writer_options_init`.
+ */
+typedef struct {
+       unsigned int version;
+
+       /**
+        * The strategy to use when adding new commits to a pre-existing commit-graph
+        * chain.
+        */
+       git_commit_graph_split_strategy_t split_strategy;
+
+       /**
+        * The number of commits in level N is less than X times the number of
+        * commits in level N + 1. Default is 2.
+        */
+       float size_multiple;
+
+       /**
+        * The number of commits in level N + 1 is more than C commits.
+        * Default is 64000.
+        */
+       size_t max_commits;
+} git_commit_graph_writer_options;
+
+#define GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION 1
+#define GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT { \
+               GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION \
+       }
+
+/**
+ * Initialize git_commit_graph_writer_options structure
+ *
+ * Initializes a `git_commit_graph_writer_options` with default values. Equivalent to
+ * creating an instance with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`.
+ *
+ * @param opts The `git_commit_graph_writer_options` struct to initialize.
+ * @param version The struct version; pass `GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION`.
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_commit_graph_writer_options_init(
+       git_commit_graph_writer_options *opts,
+       unsigned int version);
+
+/**
+ * Write a `commit-graph` file to a file.
+ *
+ * @param w The writer
+ * @param opts Pointer to git_commit_graph_writer_options struct.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_commit_graph_writer_commit(
+               git_commit_graph_writer *w,
+               git_commit_graph_writer_options *opts);
+
+/**
+ * Dump the contents of the `commit-graph` to an in-memory buffer.
+ *
+ * @param buffer Buffer where to store the contents of the `commit-graph`.
+ * @param w The writer.
+ * @param opts Pointer to git_commit_graph_writer_options struct.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_commit_graph_writer_dump(
+               git_buf *buffer,
+               git_commit_graph_writer *w,
+               git_commit_graph_writer_options *opts);
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/include/git2/sys/email.h b/include/git2/sys/email.h
new file mode 100644 (file)
index 0000000..6f4a286
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_email_h__
+#define INCLUDE_sys_git_email_h__
+
+/**
+ * @file git2/sys/email.h
+ * @brief Advanced git email creation routines
+ * @defgroup git_email Advanced git email creation routines
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Create a diff for a commit in mbox format for sending via email.
+ *
+ * @param out buffer to store the e-mail patch in
+ * @param diff the changes to include in the email
+ * @param patch_idx the patch index
+ * @param patch_count the total number of patches that will be included
+ * @param commit_id the commit id for this change
+ * @param summary the commit message for this change
+ * @param body optional text to include above the diffstat
+ * @param author the person who authored this commit
+ * @param opts email creation options
+ */
+GIT_EXTERN(int) git_email_create_from_diff(
+       git_buf *out,
+       git_diff *diff,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const char *body,
+       const git_signature *author,
+       const git_email_create_options *opts);
+
+/** @} */
+GIT_END_DECL
+#endif
index e43fde55c2fe54f14b76d93dedc561918b7fb64c..b3759416a1dd8ab5cfd6e43c2b2ae99f9e879d2d 100644 (file)
@@ -167,17 +167,18 @@ typedef void GIT_CALLBACK(git_filter_shutdown_fn)(git_filter *self);
  *
  * The `payload` will be a pointer to a reference payload for the filter.
  * This will start as NULL, but `check` can assign to this pointer for
- * later use by the `apply` callback.  Note that the value should be heap
- * allocated (not stack), so that it doesn't go away before the `apply`
+ * later use by the `stream` callback.  Note that the value should be heap
+ * allocated (not stack), so that it doesn't go away before the `stream`
  * callback can use it.  If a filter allocates and assigns a value to the
  * `payload`, it will need a `cleanup` callback to free the payload.
  */
 typedef int GIT_CALLBACK(git_filter_check_fn)(
-       git_filter  *self,
-       void       **payload, /* points to NULL ptr on entry, may be set */
+       git_filter              *self,
+       void                   **payload, /* NULL on entry, may be set */
        const git_filter_source *src,
-       const char **attr_values);
+       const char             **attr_values);
 
+#ifndef GIT_DEPRECATE_HARD
 /**
  * Callback to actually perform the data filtering
  *
@@ -189,32 +190,45 @@ typedef int GIT_CALLBACK(git_filter_check_fn)(
  *
  * The `payload` value will refer to any payload that was set by the
  * `check` callback.  It may be read from or written to as needed.
+ *
+ * @deprecated use git_filter_stream_fn
  */
 typedef int GIT_CALLBACK(git_filter_apply_fn)(
-       git_filter    *self,
-       void         **payload, /* may be read and/or set */
-       git_buf       *to,
-       const git_buf *from,
+       git_filter              *self,
+       void                   **payload, /* may be read and/or set */
+       git_buf                 *to,
+       const git_buf           *from,
        const git_filter_source *src);
+#endif
 
+/**
+ * Callback to perform the data filtering.
+ *
+ * Specified as `filter.stream`, this is a callback that filters data
+ * in a streaming manner.  This function will provide a
+ * `git_writestream` that will the original data will be written to;
+ * with that data, the `git_writestream` will then perform the filter
+ * translation and stream the filtered data out to the `next` location.
+ */
 typedef int GIT_CALLBACK(git_filter_stream_fn)(
-       git_writestream **out,
-       git_filter *self,
-       void **payload,
+       git_writestream        **out,
+       git_filter              *self,
+       void                   **payload,
        const git_filter_source *src,
-       git_writestream *next);
+       git_writestream         *next);
 
 /**
  * Callback to clean up after filtering has been applied
  *
  * Specified as `filter.cleanup`, this is an optional callback invoked
- * after the filter has been applied.  If the `check` or `apply` callbacks
- * allocated a `payload` to keep per-source filter state, use this
- * callback to free that payload and release resources as required.
+ * after the filter has been applied.  If the `check`, `apply`, or
+ * `stream` callbacks allocated a `payload` to keep per-source filter
+ * state, use this callback to free that payload and release resources
+ * as required.
  */
 typedef void GIT_CALLBACK(git_filter_cleanup_fn)(
-       git_filter *self,
-       void       *payload);
+       git_filter              *self,
+       void                    *payload);
 
 /**
  * Filter structure used to register custom filters.
@@ -248,21 +262,28 @@ struct git_filter {
        /**
         * Called to determine whether the filter should be invoked for a
         * given file.  If this function returns `GIT_PASSTHROUGH` then the
-        * `apply` function will not be invoked and the contents will be passed
-        * through unmodified.
+        * `stream` or `apply` functions will not be invoked and the
+        * contents will be passed through unmodified.
         */
        git_filter_check_fn    check;
 
+#ifdef GIT_DEPRECATE_HARD
+       void *reserved;
+#else
        /**
-        * Called to actually apply the filter to file contents.  If this
-        * function returns `GIT_PASSTHROUGH` then the contents will be passed
-        * through unmodified.
+        * Provided for backward compatibility; this will apply the
+        * filter to the given contents in a `git_buf`.  Callers should
+        * provide a `stream` function instead.
         */
        git_filter_apply_fn    apply;
+#endif
 
        /**
-        * Called to apply the filter in a streaming manner.  If this is not
-        * specified then the system will call `apply` with the whole buffer.
+        * Called to apply the filter, this function will provide a
+        * `git_writestream` that will the original data will be
+        * written to; with that data, the `git_writestream` will then
+        * perform the filter translation and stream the filtered data
+        * out to the `next` location.
         */
        git_filter_stream_fn   stream;
 
@@ -289,9 +310,9 @@ GIT_EXTERN(int) git_filter_init(git_filter *filter, unsigned int version);
  * As mentioned elsewhere, the initialize callback will not be invoked
  * immediately.  It is deferred until the filter is used in some way.
  *
- * A filter's attribute checks and `check` and `apply` callbacks will be
- * issued in order of `priority` on smudge (to workdir), and in reverse
- * order of `priority` on clean (to odb).
+ * A filter's attribute checks and `check` and `stream` (or `apply`)
+ * callbacks will be issued in order of `priority` on smudge (to
+ * workdir), and in reverse order of `priority` on clean (to odb).
  *
  * Two filters are preregistered with libgit2:
  * - GIT_FILTER_CRLF with priority 0
diff --git a/include/git2/sys/midx.h b/include/git2/sys/midx.h
new file mode 100644 (file)
index 0000000..e3d7498
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_midx_h__
+#define INCLUDE_sys_git_midx_h__
+
+#include "git2/common.h"
+#include "git2/types.h"
+
+/**
+ * @file git2/midx.h
+ * @brief Git multi-pack-index routines
+ * @defgroup git_midx Git multi-pack-index routines
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Create a new writer for `multi-pack-index` files.
+ *
+ * @param out location to store the writer pointer.
+ * @param pack_dir the directory where the `.pack` and `.idx` files are. The
+ * `multi-pack-index` file will be written in this directory, too.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_midx_writer_new(
+               git_midx_writer **out,
+               const char *pack_dir);
+
+/**
+ * Free the multi-pack-index writer and its resources.
+ *
+ * @param w the writer to free. If NULL no action is taken.
+ */
+GIT_EXTERN(void) git_midx_writer_free(git_midx_writer *w);
+
+/**
+ * Add an `.idx` file to the writer.
+ *
+ * @param w the writer
+ * @param idx_path the path of an `.idx` file.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_midx_writer_add(
+               git_midx_writer *w,
+               const char *idx_path);
+
+/**
+ * Write a `multi-pack-index` file to a file.
+ *
+ * @param w the writer
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_midx_writer_commit(
+               git_midx_writer *w);
+
+/**
+ * Dump the contents of the `multi-pack-index` to an in-memory buffer.
+ *
+ * @param midx Buffer where to store the contents of the `multi-pack-index`.
+ * @param w the writer
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_midx_writer_dump(
+               git_buf *midx,
+               git_midx_writer *w);
+
+/** @} */
+GIT_END_DECL
+#endif
index 4dba460af39f10df82ce8f4b68a00fbd5b848947..9ae0ed9b3edee764656f1545e4ba54d368fcca66 100644 (file)
@@ -84,6 +84,13 @@ struct git_odb_backend {
                git_odb_writepack **, git_odb_backend *, git_odb *odb,
                git_indexer_progress_cb progress_cb, void *progress_payload);
 
+       /**
+        * If the backend supports pack files, this will create a
+        * `multi-pack-index` file which will contain an index of all objects
+        * across all the `.pack` files.
+        */
+       int GIT_CALLBACK(writemidx)(git_odb_backend *);
+
        /**
         * "Freshens" an already existing object, updating its last-used
         * time.  This occurs when `git_odb_write` was called, but the
index 6cee42f545e15902858663e17b41b78470d06626..fee34544fa9510b569ff14fb2ef7a068c94fa0e0 100644 (file)
@@ -9,6 +9,7 @@
 #define INCLUDE_sys_git_transport_h
 
 #include "git2/net.h"
+#include "git2/transport.h"
 #include "git2/types.h"
 #include "git2/strarray.h"
 #include "git2/proxy.h"
index 4e5fe1db1a765ae14f8791591c375690b4cb080c..a3921369dad67db313eb43df4eb4db6810b2f1d1 100644 (file)
@@ -365,6 +365,18 @@ GIT_EXTERN(int) git_tag_peel(
  */
 GIT_EXTERN(int) git_tag_dup(git_tag **out, git_tag *source);
 
+/**
+ * Determine whether a tag name is valid, meaning that (when prefixed
+ * with `refs/tags/`) that it is a valid reference name, and that any
+ * additional tag name restrictions are imposed (eg, it cannot start
+ * with a `-`).
+ *
+ * @param valid output pointer to set with validity of given tag name
+ * @param name a tag name to test
+ * @return 0 on success or an error code
+ */
+GIT_EXTERN(int) git_tag_name_is_valid(int *valid, const char *name);
+
 /** @} */
 GIT_END_DECL
 #endif
index fc99ce8f3092b3116878cfd3d473169f60e946cb..5a27de9a860f8dcaf16730ae284c1e0a09411c39 100644 (file)
@@ -23,7 +23,7 @@
 GIT_BEGIN_DECL
 
 /**
- * Callback for messages recieved by the transport.
+ * Callback for messages received by the transport.
  *
  * Return a negative value to cancel the network operation.
  *
index 1a8e155fc7dc74fa67f2c351b6dd043ea614376d..f2289fc7e6c13cb615a47ecd1ce4055d8ea6ce2c 100644 (file)
@@ -334,6 +334,7 @@ GIT_EXTERN(int) git_treebuilder_insert(
  *
  * @param bld Tree builder
  * @param filename Filename of the entry to remove
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_treebuilder_remove(
        git_treebuilder *bld, const char *filename);
@@ -378,20 +379,6 @@ GIT_EXTERN(int) git_treebuilder_filter(
 GIT_EXTERN(int) git_treebuilder_write(
        git_oid *id, git_treebuilder *bld);
 
-/**
- * Write the contents of the tree builder as a tree object
- * using a shared git_buf.
- *
- * @see git_treebuilder_write
- *
- * @param oid Pointer to store the OID of the newly written tree
- * @param bld Tree builder to write
- * @param tree Shared buffer for writing the tree. Will be grown as necessary.
- * @return 0 or an error code
- */
-GIT_EXTERN(int) git_treebuilder_write_with_buffer(
-       git_oid *oid, git_treebuilder *bld, git_buf *tree);
-
 /** Callback for the tree traversal method */
 typedef int GIT_CALLBACK(git_treewalk_cb)(
        const char *root, const git_tree_entry *entry, void *payload);
@@ -477,6 +464,7 @@ typedef struct {
  * @param baseline the tree to base these changes on
  * @param nupdates the number of elements in the update list
  * @param updates the list of updates to perform
+ * @return 0 or an error code
  */
 GIT_EXTERN(int) git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates);
 
index ade0c7d3274684aab83c602d5c3cf1d79b5bd4d2..aac8e42e285772df63a91f917ae0c4b2730eccee 100644 (file)
@@ -96,12 +96,21 @@ typedef struct git_odb_stream git_odb_stream;
 /** A stream to write a packfile to the ODB */
 typedef struct git_odb_writepack git_odb_writepack;
 
+/** a writer for multi-pack-index files. */
+typedef struct git_midx_writer git_midx_writer;
+
 /** An open refs database handle. */
 typedef struct git_refdb git_refdb;
 
 /** A custom backend for refs */
 typedef struct git_refdb_backend git_refdb_backend;
 
+/** A git commit-graph */
+typedef struct git_commit_graph git_commit_graph;
+
+/** a writer for commit-graph files. */
+typedef struct git_commit_graph_writer git_commit_graph_writer;
+
 /**
  * Representation of an existing git repository,
  * including all its object contents
index c1020bbea35361f70962d9b37a010dedc9810225..3503a62781ad7d38f7692491134162cc07ed61c9 100644 (file)
@@ -7,12 +7,12 @@
 #ifndef INCLUDE_git_version_h__
 #define INCLUDE_git_version_h__
 
-#define LIBGIT2_VERSION "1.1.0"
+#define LIBGIT2_VERSION "1.3.0"
 #define LIBGIT2_VER_MAJOR 1
-#define LIBGIT2_VER_MINOR 1
+#define LIBGIT2_VER_MINOR 3
 #define LIBGIT2_VER_REVISION 0
 #define LIBGIT2_VER_PATCH 0
 
-#define LIBGIT2_SOVERSION "1.1"
+#define LIBGIT2_SOVERSION "1.3"
 
 #endif
index 049511da121ea3d134e995c71013c84297ca7a38..23084d8cd87527e7ffadc97d7ca608d057ceeeda 100644 (file)
@@ -198,6 +198,7 @@ typedef enum {
 typedef struct git_worktree_prune_options {
        unsigned int version;
 
+       /** A combination of `git_worktree_prune_t` */
        uint32_t flags;
 } git_worktree_prune_options;
 
index 5e74f3bd5afc5e4f245e28d44e13c14a2a49224d..e2e672f9fe6f76b37f972802e9da7ce42f4795ea 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "libgit2",
-  "version": "1.1.0",
+  "version": "1.3.0",
   "repo": "https://github.com/libgit2/libgit2",
   "description": " A cross-platform, linkable library implementation of Git that you can use in your application.",
   "install": "mkdir build && cd build && cmake .. && cmake --build ."
diff --git a/script/thread-sanitizer.supp b/script/thread-sanitizer.supp
new file mode 100644 (file)
index 0000000..97d2304
--- /dev/null
@@ -0,0 +1,26 @@
+# In attr_file_free, the locks are acquired in the opposite order in which they
+# are normally acquired. This is probably something worth fixing to have a
+# consistent lock hierarchy that is easy to understand.
+deadlock:attr_cache_lock
+
+# git_mwindow_file_register has the possibility of evicting some files from the
+# global cache. In order to avoid races and closing files that are currently
+# being accessed, before evicting any file it will attempt to acquire that
+# file's lock. Finally, git_mwindow_file_register is typically called with a
+# file lock held, because the caller will use the fd in the mwf immediately
+# after registering it. This causes ThreadSanitizer to observe different orders
+# of acquisition of the mutex (which implies a possibility of a deadlock),
+# _but_ since the files are added to the cache after other files have been
+# evicted, there cannot be a case where mwf A is trying to be registered while
+# evicting mwf B concurrently and viceversa: at most one of them can be present
+# in the cache.
+deadlock:git_mwindow_file_register
+
+# When invoking the time/timezone functions from git_signature_now(), they
+# access libc methods that need to be instrumented to correctly analyze the
+# data races.
+called_from_lib:libc.so.6
+
+# TODO(#5592): Investigate and fix this. It can be triggered by the `thread`
+# test suite.
+race:git_filter_list__load_ext
index d938aa9c9c783534245f979d114bc737ce677a7f..8c4549f62bed92429db16c7288f3ba440967cffe 100644 (file)
        ...
 }
 
+{
+       ignore-openssl-init-leak
+       Memcheck:Leak
+       ...
+       fun:git_openssl_stream_global_init
+       ...
+}
+
+{
+       ignore-openssl-legacy-init-leak
+       Memcheck:Leak
+       ...
+       fun:OPENSSL_init_ssl__legacy
+       ...
+}
+
+{
+       ignore-openssl-malloc-leak
+       Memcheck:Leak
+       ...
+       fun:git_openssl_malloc
+       ...
+}
+
+{
+       ignore-openssl-realloc-leak
+       Memcheck:Leak
+       ...
+       fun:git_openssl_realloc
+       ...
+}
+
 {
        ignore-glibc-getaddrinfo-cache
        Memcheck:Leak
        ...
 }
 
+{
+       ignore-libssh2-session-create
+       Memcheck:Leak
+       ...
+       fun:_git_ssh_session_create
+       ...
+}
+
+{
+       ignore-libssh2-setup-conn
+       Memcheck:Leak
+       ...
+       fun:_git_ssh_setup_conn
+       ...
+}
+
 {
        ignore-libssh2-gcrypt-control-leak
        Memcheck:Leak
        obj:*libcrypto.so*
        ...
 }
+
+{
+       ignore-dlopen-leak
+       Memcheck:Leak
+       ...
+       fun:dlopen
+       ...
+}
+
+{
+       ignore-dlopen-leak
+       Memcheck:Leak
+       ...
+       fun:_dlerror_run
+       ...
+}
index d01cc6458e3fee2b493445d2aeb1d29899380d1c..fdb367335b4f8063a21d31ee7e91ec81f5863767 100644 (file)
@@ -6,7 +6,18 @@ IF(DEBUG_POOL)
 ENDIF()
 ADD_FEATURE_INFO(debugpool GIT_DEBUG_POOL "debug pool allocator")
 
+IF(DEBUG_STRICT_ALLOC)
+       SET(GIT_DEBUG_STRICT_ALLOC 1)
+ENDIF()
+ADD_FEATURE_INFO(debugalloc GIT_DEBUG_STRICT_ALLOC "debug strict allocators")
+
+IF(DEBUG_STRICT_OPEN)
+       SET(GIT_DEBUG_STRICT_OPEN 1)
+ENDIF()
+ADD_FEATURE_INFO(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open")
+
 INCLUDE(PkgBuildConfig)
+INCLUDE(SanitizeBool)
 
 # This variable will contain the libraries we need to put into
 # libgit2.pc's Requires.private. That is, what we're linking to or
@@ -32,10 +43,10 @@ IF(ENABLE_TRACE)
 ENDIF()
 ADD_FEATURE_INFO(tracing GIT_TRACE "tracing support")
 
-CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
 IF (HAVE_FUTIMENS)
        SET(GIT_USE_FUTIMENS 1)
 ENDIF ()
+ADD_FEATURE_INFO(futimens GIT_USE_FUTIMENS "futimens support")
 
 CHECK_PROTOTYPE_DEFINITION(qsort_r
        "void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *))"
@@ -186,7 +197,12 @@ ELSE()
 ENDIF()
 
 # Optional external dependency: zlib
-IF(NOT USE_BUNDLED_ZLIB)
+SanitizeBool(USE_BUNDLED_ZLIB)
+IF(USE_BUNDLED_ZLIB STREQUAL ON)
+       SET(USE_BUNDLED_ZLIB "Bundled")
+ENDIF()
+
+IF(USE_BUNDLED_ZLIB STREQUAL "OFF")
        FIND_PACKAGE(ZLIB)
        IF(ZLIB_FOUND)
                LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${ZLIB_INCLUDE_DIRS})
@@ -201,7 +217,12 @@ IF(NOT USE_BUNDLED_ZLIB)
                MESSAGE(STATUS "zlib was not found; using bundled 3rd-party sources." )
        ENDIF()
 ENDIF()
-IF(USE_BUNDLED_ZLIB OR NOT ZLIB_FOUND)
+IF(USE_BUNDLED_ZLIB STREQUAL "Chromium")
+       ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/chromium-zlib" "${libgit2_BINARY_DIR}/deps/chromium-zlib")
+       LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/chromium-zlib")
+       LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:chromium_zlib>)
+       ADD_FEATURE_INFO(zlib ON "using (Chromium) bundled zlib")
+ELSEIF(USE_BUNDLED_ZLIB OR NOT ZLIB_FOUND)
        ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/zlib" "${libgit2_BINARY_DIR}/deps/zlib")
        LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/zlib")
        LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:zlib>)
@@ -211,6 +232,13 @@ ENDIF()
 # Optional external dependency: libssh2
 IF (USE_SSH)
        FIND_PKGLIBRARIES(LIBSSH2 libssh2)
+       IF (NOT LIBSSH2_FOUND)
+               FIND_PACKAGE(LibSSH2)
+               SET(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR})
+               GET_FILENAME_COMPONENT(LIBSSH2_LIBRARY_DIRS "${LIBSSH2_LIBRARY}" DIRECTORY)
+               SET(LIBSSH2_LIBRARIES ${LIBSSH2_LIBRARY})
+               SET(LIBSSH2_LDFLAGS "-lssh2")
+       ENDIF()
 ENDIF()
 IF (LIBSSH2_FOUND)
        SET(GIT_SSH 1)
@@ -374,7 +402,7 @@ if(SONAME)
        set_target_properties(git2 PROPERTIES VERSION ${libgit2_VERSION})
        set_target_properties(git2 PROPERTIES SOVERSION "${libgit2_VERSION_MAJOR}.${libgit2_VERSION_MINOR}")
        if(LIBGIT2_FILENAME)
-               target_compile_definitions(git2internal PRIVATE LIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
+               target_compile_definitions(git2 PRIVATE LIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
                set_target_properties(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
        elseif(DEFINED LIBGIT2_PREFIX)
                set_target_properties(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}")
index 51c4d80292eee3ee96893bb627b538090e148ded..2820d84a2197efe46ec7f9ce28080530d479daac 100644 (file)
@@ -6,16 +6,29 @@
  */
 
 #include "alloc.h"
+#include "runtime.h"
 
+#include "allocators/failalloc.h"
 #include "allocators/stdalloc.h"
-#include "allocators/win32_crtdbg.h"
-
-git_allocator git__allocator;
+#include "allocators/win32_leakcheck.h"
+
+/* Fail any allocation until git_libgit2_init is called. */
+git_allocator git__allocator = {
+       git_failalloc_malloc,
+       git_failalloc_calloc,
+       git_failalloc_strdup,
+       git_failalloc_strndup,
+       git_failalloc_substrdup,
+       git_failalloc_realloc,
+       git_failalloc_reallocarray,
+       git_failalloc_mallocarray,
+       git_failalloc_free
+};
 
 static int setup_default_allocator(void)
 {
-#if defined(GIT_MSVC_CRTDBG)
-       return git_win32_crtdbg_init_allocator(&git__allocator);
+#if defined(GIT_WIN32_LEAKCHECK)
+       return git_win32_leakcheck_init_allocator(&git__allocator);
 #else
        return git_stdalloc_init_allocator(&git__allocator);
 #endif
@@ -24,10 +37,10 @@ static int setup_default_allocator(void)
 int git_allocator_global_init(void)
 {
        /*
-        * We don't want to overwrite any allocator which has been set before
-        * the init function is called.
+        * We don't want to overwrite any allocator which has been set
+        * before the init function is called.
         */
-       if (git__allocator.gmalloc != NULL)
+       if (git__allocator.gmalloc != git_failalloc_malloc)
                return 0;
 
        return setup_default_allocator();
diff --git a/src/allocators/failalloc.c b/src/allocators/failalloc.c
new file mode 100644 (file)
index 0000000..5257d1d
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "failalloc.h"
+
+void *git_failalloc_malloc(size_t len, const char *file, int line)
+{
+       GIT_UNUSED(len);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+       GIT_UNUSED(nelem);
+       GIT_UNUSED(elsize);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+char *git_failalloc_strdup(const char *str, const char *file, int line)
+{
+       GIT_UNUSED(str);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line)
+{
+       GIT_UNUSED(str);
+       GIT_UNUSED(n);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line)
+{
+       GIT_UNUSED(start);
+       GIT_UNUSED(n);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line)
+{
+       GIT_UNUSED(ptr);
+       GIT_UNUSED(size);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
+{
+       GIT_UNUSED(ptr);
+       GIT_UNUSED(nelem);
+       GIT_UNUSED(elsize);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line)
+{
+       GIT_UNUSED(nelem);
+       GIT_UNUSED(elsize);
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       return NULL;
+}
+
+void git_failalloc_free(void *ptr)
+{
+       GIT_UNUSED(ptr);
+}
diff --git a/src/allocators/failalloc.h b/src/allocators/failalloc.h
new file mode 100644 (file)
index 0000000..6115e51
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_allocators_failalloc_h__
+#define INCLUDE_allocators_failalloc_h__
+
+#include "common.h"
+
+extern void *git_failalloc_malloc(size_t len, const char *file, int line);
+extern void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line);
+extern char *git_failalloc_strdup(const char *str, const char *file, int line);
+extern char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line);
+extern char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line);
+extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line);
+extern void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line);
+extern void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line);
+extern void git_failalloc_free(void *ptr);
+
+#endif
index c4938e32b6bcb9318d7004ba7578a01a4d0a0f32..2b36d9f3df3e87641b5efcb9eee9ca56f4ba2e1d 100644 (file)
@@ -9,34 +9,56 @@
 
 static void *stdalloc__malloc(size_t len, const char *file, int line)
 {
-       void *ptr = malloc(len);
+       void *ptr;
 
        GIT_UNUSED(file);
        GIT_UNUSED(line);
 
-       if (!ptr) git_error_set_oom();
+#ifdef GIT_DEBUG_STRICT_ALLOC
+       if (!len)
+               return NULL;
+#endif
+
+       ptr = malloc(len);
+
+       if (!ptr)
+               git_error_set_oom();
+
        return ptr;
 }
 
 static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line)
 {
-       void *ptr = calloc(nelem, elsize);
+       void *ptr;
 
        GIT_UNUSED(file);
        GIT_UNUSED(line);
 
-       if (!ptr) git_error_set_oom();
+#ifdef GIT_DEBUG_STRICT_ALLOC
+       if (!elsize || !nelem)
+               return NULL;
+#endif
+
+       ptr = calloc(nelem, elsize);
+
+       if (!ptr)
+               git_error_set_oom();
+
        return ptr;
 }
 
 static char *stdalloc__strdup(const char *str, const char *file, int line)
 {
-       char *ptr = strdup(str);
+       char *ptr;
 
        GIT_UNUSED(file);
        GIT_UNUSED(line);
 
-       if (!ptr) git_error_set_oom();
+       ptr = strdup(str);
+
+       if (!ptr)
+               git_error_set_oom();
+
        return ptr;
 }
 
@@ -48,7 +70,7 @@ static char *stdalloc__strndup(const char *str, size_t n, const char *file, int
        length = p_strnlen(str, n);
 
        if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
-               !(ptr = stdalloc__malloc(alloclength, file, line)))
+           !(ptr = stdalloc__malloc(alloclength, file, line)))
                return NULL;
 
        if (length)
@@ -65,7 +87,7 @@ static char *stdalloc__substrdup(const char *start, size_t n, const char *file,
        size_t alloclen;
 
        if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
-               !(ptr = stdalloc__malloc(alloclen, file, line)))
+           !(ptr = stdalloc__malloc(alloclen, file, line)))
                return NULL;
 
        memcpy(ptr, start, n);
@@ -75,12 +97,21 @@ static char *stdalloc__substrdup(const char *start, size_t n, const char *file,
 
 static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line)
 {
-       void *new_ptr = realloc(ptr, size);
+       void *new_ptr;
 
        GIT_UNUSED(file);
        GIT_UNUSED(line);
 
-       if (!new_ptr) git_error_set_oom();
+#ifdef GIT_DEBUG_STRICT_ALLOC
+       if (!size)
+               return NULL;
+#endif
+
+       new_ptr = realloc(ptr, size);
+
+       if (!new_ptr)
+               git_error_set_oom();
+
        return new_ptr;
 }
 
diff --git a/src/allocators/win32_crtdbg.c b/src/allocators/win32_crtdbg.c
deleted file mode 100644 (file)
index 1187e2f..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "win32_crtdbg.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-
-#include "win32/w32_crtdbg_stacktrace.h"
-
-static void *crtdbg__malloc(size_t len, const char *file, int line)
-{
-       void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-       if (!ptr) git_error_set_oom();
-       return ptr;
-}
-
-static void *crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
-{
-       void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-       if (!ptr) git_error_set_oom();
-       return ptr;
-}
-
-static char *crtdbg__strdup(const char *str, const char *file, int line)
-{
-       char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-       if (!ptr) git_error_set_oom();
-       return ptr;
-}
-
-static char *crtdbg__strndup(const char *str, size_t n, const char *file, int line)
-{
-       size_t length = 0, alloclength;
-       char *ptr;
-
-       length = p_strnlen(str, n);
-
-       if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
-               !(ptr = crtdbg__malloc(alloclength, file, line)))
-               return NULL;
-
-       if (length)
-               memcpy(ptr, str, length);
-
-       ptr[length] = '\0';
-
-       return ptr;
-}
-
-static char *crtdbg__substrdup(const char *start, size_t n, const char *file, int line)
-{
-       char *ptr;
-       size_t alloclen;
-
-       if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
-               !(ptr = crtdbg__malloc(alloclen, file, line)))
-               return NULL;
-
-       memcpy(ptr, start, n);
-       ptr[n] = '\0';
-       return ptr;
-}
-
-static void *crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
-{
-       void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-       if (!new_ptr) git_error_set_oom();
-       return new_ptr;
-}
-
-static void *crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
-{
-       size_t newsize;
-
-       if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
-               return NULL;
-
-       return crtdbg__realloc(ptr, newsize, file, line);
-}
-
-static void *crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
-{
-       return crtdbg__reallocarray(NULL, nelem, elsize, file, line);
-}
-
-static void crtdbg__free(void *ptr)
-{
-       free(ptr);
-}
-
-int git_win32_crtdbg_init_allocator(git_allocator *allocator)
-{
-       allocator->gmalloc = crtdbg__malloc;
-       allocator->gcalloc = crtdbg__calloc;
-       allocator->gstrdup = crtdbg__strdup;
-       allocator->gstrndup = crtdbg__strndup;
-       allocator->gsubstrdup = crtdbg__substrdup;
-       allocator->grealloc = crtdbg__realloc;
-       allocator->greallocarray = crtdbg__reallocarray;
-       allocator->gmallocarray = crtdbg__mallocarray;
-       allocator->gfree = crtdbg__free;
-       return 0;
-}
-
-#else
-
-int git_win32_crtdbg_init_allocator(git_allocator *allocator)
-{
-       GIT_UNUSED(allocator);
-       git_error_set(GIT_EINVALID, "crtdbg memory allocator not available");
-       return -1;
-}
-
-#endif
diff --git a/src/allocators/win32_crtdbg.h b/src/allocators/win32_crtdbg.h
deleted file mode 100644 (file)
index 754c6b6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_allocators_crtdbg_h
-#define INCLUDE_allocators_crtdbg_h
-
-#include "common.h"
-
-#include "alloc.h"
-
-int git_win32_crtdbg_init_allocator(git_allocator *allocator);
-
-#endif
diff --git a/src/allocators/win32_leakcheck.c b/src/allocators/win32_leakcheck.c
new file mode 100644 (file)
index 0000000..fe06a14
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "win32_leakcheck.h"
+
+#if defined(GIT_WIN32_LEAKCHECK)
+
+#include "win32/w32_leakcheck.h"
+
+static void *leakcheck_malloc(size_t len, const char *file, int line)
+{
+       void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
+       if (!ptr) git_error_set_oom();
+       return ptr;
+}
+
+static void *leakcheck_calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+       void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
+       if (!ptr) git_error_set_oom();
+       return ptr;
+}
+
+static char *leakcheck_strdup(const char *str, const char *file, int line)
+{
+       char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
+       if (!ptr) git_error_set_oom();
+       return ptr;
+}
+
+static char *leakcheck_strndup(const char *str, size_t n, const char *file, int line)
+{
+       size_t length = 0, alloclength;
+       char *ptr;
+
+       length = p_strnlen(str, n);
+
+       if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
+               !(ptr = leakcheck_malloc(alloclength, file, line)))
+               return NULL;
+
+       if (length)
+               memcpy(ptr, str, length);
+
+       ptr[length] = '\0';
+
+       return ptr;
+}
+
+static char *leakcheck_substrdup(const char *start, size_t n, const char *file, int line)
+{
+       char *ptr;
+       size_t alloclen;
+
+       if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
+               !(ptr = leakcheck_malloc(alloclen, file, line)))
+               return NULL;
+
+       memcpy(ptr, start, n);
+       ptr[n] = '\0';
+       return ptr;
+}
+
+static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line)
+{
+       void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
+       if (!new_ptr) git_error_set_oom();
+       return new_ptr;
+}
+
+static void *leakcheck_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
+{
+       size_t newsize;
+
+       if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
+               return NULL;
+
+       return leakcheck_realloc(ptr, newsize, file, line);
+}
+
+static void *leakcheck_mallocarray(size_t nelem, size_t elsize, const char *file, int line)
+{
+       return leakcheck_reallocarray(NULL, nelem, elsize, file, line);
+}
+
+static void leakcheck_free(void *ptr)
+{
+       free(ptr);
+}
+
+int git_win32_leakcheck_init_allocator(git_allocator *allocator)
+{
+       allocator->gmalloc = leakcheck_malloc;
+       allocator->gcalloc = leakcheck_calloc;
+       allocator->gstrdup = leakcheck_strdup;
+       allocator->gstrndup = leakcheck_strndup;
+       allocator->gsubstrdup = leakcheck_substrdup;
+       allocator->grealloc = leakcheck_realloc;
+       allocator->greallocarray = leakcheck_reallocarray;
+       allocator->gmallocarray = leakcheck_mallocarray;
+       allocator->gfree = leakcheck_free;
+       return 0;
+}
+
+#else
+
+int git_win32_leakcheck_init_allocator(git_allocator *allocator)
+{
+       GIT_UNUSED(allocator);
+       git_error_set(GIT_EINVALID, "leakcheck memory allocator not available");
+       return -1;
+}
+
+#endif
diff --git a/src/allocators/win32_leakcheck.h b/src/allocators/win32_leakcheck.h
new file mode 100644 (file)
index 0000000..089690f
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_allocators_win32_leakcheck_h
+#define INCLUDE_allocators_win32_leakcheck_h
+
+#include "common.h"
+
+#include "alloc.h"
+
+int git_win32_leakcheck_init_allocator(git_allocator *allocator);
+
+#endif
index 5d4f3708206b5e7efc8807a75a0c7417c14e9f47..e489476796f929b21c5482ad654f16d66a6dcdba 100644 (file)
@@ -26,7 +26,8 @@ static int annotated_commit_init(
        git_annotated_commit *annotated_commit;
        int error = 0;
 
-       assert(out && commit);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(commit);
 
        *out = NULL;
 
@@ -63,7 +64,9 @@ static int annotated_commit_init_from_id(
        git_commit *commit = NULL;
        int error = 0;
 
-       assert(out && repo && id);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(id);
 
        *out = NULL;
 
@@ -100,7 +103,9 @@ int git_annotated_commit_from_revspec(
        git_object *obj, *commit;
        int error;
 
-       assert(out && repo && revspec);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(revspec);
 
        if ((error = git_revparse_single(&obj, repo, revspec)) < 0)
                return error;
@@ -126,7 +131,9 @@ int git_annotated_commit_from_ref(
        git_object *peeled;
        int error = 0;
 
-       assert(out && repo && ref);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(ref);
 
        *out = NULL;
 
@@ -154,11 +161,12 @@ int git_annotated_commit_from_head(
        git_reference *head;
        int error;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
-    if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
+       if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
                return -1;
 
        error = git_annotated_commit_from_ref(out, repo, head);
@@ -174,7 +182,11 @@ int git_annotated_commit_from_fetchhead(
        const char *remote_url,
        const git_oid *id)
 {
-       assert(repo && id && branch_name && remote_url);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(branch_name);
+       GIT_ASSERT_ARG(remote_url);
+       GIT_ASSERT_ARG(id);
 
        if (annotated_commit_init_from_id(out, repo, id, branch_name) < 0)
                return -1;
@@ -192,14 +204,14 @@ int git_annotated_commit_from_fetchhead(
 const git_oid *git_annotated_commit_id(
        const git_annotated_commit *annotated_commit)
 {
-       assert(annotated_commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(annotated_commit, NULL);
        return git_commit_id(annotated_commit->commit);
 }
 
 const char *git_annotated_commit_ref(
        const git_annotated_commit *annotated_commit)
 {
-       assert(annotated_commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(annotated_commit, NULL);
        return annotated_commit->ref_name;
 }
 
index b0be2d8e6637380edc2941895bbf234d1eebd959..7c65cd79db6705cc4fb99e2c030a1e43fce68b55 100644 (file)
@@ -5,8 +5,6 @@
  * a Linking Exception. For full terms see the included COPYING file.
  */
 
-#include "apply.h"
-
 #include "git2/apply.h"
 #include "git2/patch.h"
 #include "git2/filter.h"
@@ -21,6 +19,7 @@
 #include "zstream.h"
 #include "reader.h"
 #include "index.h"
+#include "apply.h"
 
 typedef struct {
        /* The lines that we allocate ourself are allocated out of the pool.
@@ -399,7 +398,11 @@ int git_apply__patch(
        unsigned int mode = 0;
        int error = 0;
 
-       assert(contents_out && filename_out && mode_out && (source || !source_len) && patch);
+       GIT_ASSERT_ARG(contents_out);
+       GIT_ASSERT_ARG(filename_out);
+       GIT_ASSERT_ARG(mode_out);
+       GIT_ASSERT_ARG(source || !source_len);
+       GIT_ASSERT_ARG(patch);
 
        if (given_opts)
                memcpy(&ctx.opts, given_opts, sizeof(git_apply_options));
@@ -624,7 +627,10 @@ int git_apply_to_tree(
        size_t i;
        int error = 0;
 
-       assert(out && repo && preimage && diff);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(preimage);
+       GIT_ASSERT_ARG(diff);
 
        *out = NULL;
 
@@ -772,6 +778,8 @@ done:
 
 int git_apply_options_init(git_apply_options *opts, unsigned int version)
 {
+       GIT_ASSERT_ARG(opts);
+
        GIT_INIT_STRUCTURE_FROM_TEMPLATE(
                opts, version, git_apply_options, GIT_APPLY_OPTIONS_INIT);
        return 0;
@@ -805,7 +813,8 @@ int git_apply(
        git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
        int error = GIT_EINVALID;
 
-       assert(repo && diff);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(diff);
 
        GIT_ERROR_CHECK_VERSION(
                given_opts, GIT_APPLY_OPTIONS_VERSION, "git_apply_options");
@@ -829,7 +838,7 @@ int git_apply(
                error = git_reader_for_workdir(&pre_reader, repo, false);
                break;
        default:
-               assert(false);
+               GIT_ASSERT(false);
        }
 
        if (error < 0)
@@ -869,7 +878,7 @@ int git_apply(
                error = git_apply__to_workdir(repo, diff, preimage, postimage, location, &opts);
                break;
        default:
-               assert(false);
+               GIT_ASSERT(false);
        }
 
        if (error < 0)
index 03537e7966655c26508491d71ad7e3775fae6ab4..e97688b365fe5ac22fdffe356dd19054a03d2ea9 100644 (file)
@@ -41,8 +41,8 @@
 
 typedef git_array_t(char) git_array_generic_t;
 
-/* use a generic array for growth so this can return the new item */
-GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
+/* use a generic array for growth, return 0 on success */
+GIT_INLINE(int) git_array_grow(void *_a, size_t item_size)
 {
        volatile git_array_generic_t *a = _a;
        size_t new_size;
@@ -59,24 +59,24 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
        if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
                goto on_oom;
 
-       a->ptr = new_array; a->asize = new_size; a->size++;
-       return a->ptr + (a->size - 1) * item_size;
+       a->ptr = new_array;
+       a->asize = new_size;
+       return 0;
 
 on_oom:
        git_array_clear(*a);
-       return NULL;
+       return -1;
 }
 
 #define git_array_alloc(a) \
-       (((a).size >= (a).asize) ? \
-       git_array_grow(&(a), sizeof(*(a).ptr)) : \
-       ((a).ptr ? &(a).ptr[(a).size++] : NULL))
+       (((a).size < (a).asize || git_array_grow(&(a), sizeof(*(a).ptr)) == 0) ? \
+       &(a).ptr[(a).size++] : (void *)NULL)
 
-#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL)
+#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : (void *)NULL)
 
-#define git_array_pop(a) ((a).size ? &(a).ptr[--(a).size] : NULL)
+#define git_array_pop(a) ((a).size ? &(a).ptr[--(a).size] : (void *)NULL)
 
-#define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL)
+#define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : (void *)NULL)
 
 #define git_array_size(a) (a).size
 
index bd517cde3aeb5cbd64a18494c26f1dc18b6ae6c6..95b49e3de41132abf778c894724919607c0f400e 100644 (file)
@@ -36,16 +36,16 @@ git_attr_value_t git_attr_value(const char *attr)
 static int collect_attr_files(
        git_repository *repo,
        git_attr_session *attr_session,
-       uint32_t flags,
+       git_attr_options *opts,
        const char *path,
        git_vector *files);
 
 static void release_attr_files(git_vector *files);
 
-int git_attr_get(
+int git_attr_get_ext(
        const char **value,
        git_repository *repo,
-       uint32_t flags,
+       git_attr_options *opts,
        const char *pathname,
        const char *name)
 {
@@ -58,7 +58,10 @@ int git_attr_get(
        git_attr_rule *rule;
        git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
 
-       assert(value && repo && name);
+       GIT_ASSERT_ARG(value);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
+       GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options");
 
        *value = NULL;
 
@@ -68,7 +71,7 @@ int git_attr_get(
        if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
                return -1;
 
-       if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
+       if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0)
                goto cleanup;
 
        memset(&attr, 0, sizeof(attr));
@@ -95,6 +98,20 @@ cleanup:
        return error;
 }
 
+int git_attr_get(
+       const char **value,
+       git_repository *repo,
+       uint32_t flags,
+       const char *pathname,
+       const char *name)
+{
+       git_attr_options opts = GIT_ATTR_OPTIONS_INIT;
+
+       opts.flags = flags;
+
+       return git_attr_get_ext(value, repo, &opts, pathname, name);
+}
+
 
 typedef struct {
        git_attr_name name;
@@ -105,7 +122,7 @@ int git_attr_get_many_with_session(
        const char **values,
        git_repository *repo,
        git_attr_session *attr_session,
-       uint32_t flags,
+       git_attr_options *opts,
        const char *pathname,
        size_t num_attr,
        const char **names)
@@ -123,7 +140,11 @@ int git_attr_get_many_with_session(
        if (!num_attr)
                return 0;
 
-       assert(values && repo && names);
+       GIT_ASSERT_ARG(values);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(pathname);
+       GIT_ASSERT_ARG(names);
+       GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options");
 
        if (git_repository_is_bare(repo))
                dir_flag = GIT_DIR_FLAG_FALSE;
@@ -131,7 +152,7 @@ int git_attr_get_many_with_session(
        if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
                return -1;
 
-       if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
+       if ((error = collect_attr_files(repo, attr_session, opts, pathname, &files)) < 0)
                goto cleanup;
 
        info = git__calloc(num_attr, sizeof(attr_get_many_info));
@@ -185,8 +206,24 @@ int git_attr_get_many(
        size_t num_attr,
        const char **names)
 {
+       git_attr_options opts = GIT_ATTR_OPTIONS_INIT;
+
+       opts.flags = flags;
+
        return git_attr_get_many_with_session(
-               values, repo, NULL, flags, pathname, num_attr, names);
+               values, repo, NULL, &opts, pathname, num_attr, names);
+}
+
+int git_attr_get_many_ext(
+       const char **values,
+       git_repository *repo,
+       git_attr_options *opts,
+       const char *pathname,
+       size_t num_attr,
+       const char **names)
+{
+       return git_attr_get_many_with_session(
+               values, repo, NULL, opts, pathname, num_attr, names);
 }
 
 int git_attr_foreach(
@@ -195,6 +232,20 @@ int git_attr_foreach(
        const char *pathname,
        int (*callback)(const char *name, const char *value, void *payload),
        void *payload)
+{
+       git_attr_options opts = GIT_ATTR_OPTIONS_INIT;
+
+       opts.flags = flags;
+
+       return git_attr_foreach_ext(repo, &opts, pathname, callback, payload);
+}
+
+int git_attr_foreach_ext(
+       git_repository *repo,
+       git_attr_options *opts,
+       const char *pathname,
+       int (*callback)(const char *name, const char *value, void *payload),
+       void *payload)
 {
        int error;
        git_attr_path path;
@@ -206,7 +257,9 @@ int git_attr_foreach(
        git_strmap *seen = NULL;
        git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
 
-       assert(repo && callback);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(callback);
+       GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options");
 
        if (git_repository_is_bare(repo))
                dir_flag = GIT_DIR_FLAG_FALSE;
@@ -214,7 +267,7 @@ int git_attr_foreach(
        if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
                return -1;
 
-       if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
+       if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0 ||
            (error = git_strmap_new(&seen)) < 0)
                goto cleanup;
 
@@ -247,26 +300,43 @@ cleanup:
        return error;
 }
 
-static int preload_attr_file(
+static int preload_attr_source(
        git_repository *repo,
        git_attr_session *attr_session,
-       git_attr_file_source source,
-       const char *base,
-       const char *file,
-       bool allow_macros)
+       git_attr_file_source *source)
 {
        int error;
        git_attr_file *preload = NULL;
 
-       if (!file)
+       if (!source)
                return 0;
-       if (!(error = git_attr_cache__get(&preload, repo, attr_session, source, base, file,
-                                         git_attr_file__parse_buffer, allow_macros)))
+
+       error = git_attr_cache__get(&preload, repo, attr_session, source,
+                                   git_attr_file__parse_buffer, true);
+
+       if (!error)
                git_attr_file__free(preload);
 
        return error;
 }
 
+GIT_INLINE(int) preload_attr_file(
+       git_repository *repo,
+       git_attr_session *attr_session,
+       const char *base,
+       const char *filename)
+{
+       git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE };
+
+       if (!filename)
+               return 0;
+
+       source.base = base;
+       source.filename = filename;
+
+       return preload_attr_source(repo, attr_session, &source);
+}
+
 static int system_attr_file(
        git_buf *out,
        git_attr_session *attr_session)
@@ -308,9 +378,12 @@ static int system_attr_file(
 static int attr_setup(
        git_repository *repo,
        git_attr_session *attr_session,
-       uint32_t flags)
+       git_attr_options *opts)
 {
-       git_buf path = GIT_BUF_INIT;
+       git_buf system = GIT_BUF_INIT, info = GIT_BUF_INIT;
+       git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE, NULL };
+       git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_HEAD, NULL, GIT_ATTR_FILE, NULL };
+       git_attr_file_source commit_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL };
        git_index *idx = NULL;
        const char *workdir;
        int error = 0;
@@ -326,45 +399,56 @@ static int attr_setup(
         * definitions will be available for later file parsing.
         */
 
-       if ((error = system_attr_file(&path, attr_session)) < 0 ||
-           (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
-                                      NULL, path.ptr, true)) < 0) {
+       if ((error = system_attr_file(&system, attr_session)) < 0 ||
+           (error = preload_attr_file(repo, attr_session, NULL, system.ptr)) < 0) {
                if (error != GIT_ENOTFOUND)
                        goto out;
+
+               error = 0;
        }
 
-       if ((error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
-                                      NULL, git_repository_attr_cache(repo)->cfg_attr_file, true)) < 0)
+       if ((error = preload_attr_file(repo, attr_session, NULL,
+                                      git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
                goto out;
 
-       git_buf_clear(&path); /* git_repository_item_path expects an empty buffer, because it uses git_buf_set */
-       if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
-           (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
-                                      path.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) {
+       if ((error = git_repository_item_path(&info, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
+           (error = preload_attr_file(repo, attr_session, info.ptr, GIT_ATTR_FILE_INREPO)) < 0) {
                if (error != GIT_ENOTFOUND)
                        goto out;
+
+               error = 0;
        }
 
        if ((workdir = git_repository_workdir(repo)) != NULL &&
-           (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
-                                      workdir, GIT_ATTR_FILE, true)) < 0)
+           (error = preload_attr_file(repo, attr_session, workdir, GIT_ATTR_FILE)) < 0)
                        goto out;
 
        if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
-           (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_INDEX,
-                                      NULL, GIT_ATTR_FILE, true)) < 0)
+           (error = preload_attr_source(repo, attr_session, &index_source)) < 0)
                        goto out;
 
-       if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 &&
-           (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_HEAD,
-                                      NULL, GIT_ATTR_FILE, true)) < 0)
+       if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) &&
+           (error = preload_attr_source(repo, attr_session, &head_source)) < 0)
                goto out;
 
+       if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0)) {
+#ifndef GIT_DEPRECATE_HARD
+               if (opts->commit_id)
+                       commit_source.commit_id = opts->commit_id;
+               else
+#endif
+               commit_source.commit_id = &opts->attr_commit_id;
+
+               if ((error = preload_attr_source(repo, attr_session, &commit_source)) < 0)
+                       goto out;
+       }
+
        if (attr_session)
                attr_session->init_setup = 1;
 
 out:
-       git_buf_dispose(&path);
+       git_buf_dispose(&system);
+       git_buf_dispose(&info);
 
        return error;
 }
@@ -378,6 +462,9 @@ int git_attr_add_macro(
        git_attr_rule *macro = NULL;
        git_pool *pool;
 
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
+
        if ((error = git_attr_cache__init(repo)) < 0)
                return error;
 
@@ -406,56 +493,62 @@ int git_attr_add_macro(
 typedef struct {
        git_repository *repo;
        git_attr_session *attr_session;
-       uint32_t flags;
+       git_attr_options *opts;
        const char *workdir;
        git_index *index;
        git_vector *files;
 } attr_walk_up_info;
 
 static int attr_decide_sources(
-       uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs)
+       uint32_t flags,
+       bool has_wd,
+       bool has_index,
+       git_attr_file_source_t *srcs)
 {
        int count = 0;
 
        switch (flags & 0x03) {
        case GIT_ATTR_CHECK_FILE_THEN_INDEX:
                if (has_wd)
-                       srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
+                       srcs[count++] = GIT_ATTR_FILE_SOURCE_FILE;
                if (has_index)
-                       srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
+                       srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX;
                break;
        case GIT_ATTR_CHECK_INDEX_THEN_FILE:
                if (has_index)
-                       srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
+                       srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX;
                if (has_wd)
-                       srcs[count++] = GIT_ATTR_FILE__FROM_FILE;
+                       srcs[count++] = GIT_ATTR_FILE_SOURCE_FILE;
                break;
        case GIT_ATTR_CHECK_INDEX_ONLY:
                if (has_index)
-                       srcs[count++] = GIT_ATTR_FILE__FROM_INDEX;
+                       srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX;
                break;
        }
 
        if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0)
-               srcs[count++] = GIT_ATTR_FILE__FROM_HEAD;
+               srcs[count++] = GIT_ATTR_FILE_SOURCE_HEAD;
+
+       if ((flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0)
+               srcs[count++] = GIT_ATTR_FILE_SOURCE_COMMIT;
 
        return count;
 }
 
-static int push_attr_file(
+static int push_attr_source(
        git_repository *repo,
        git_attr_session *attr_session,
        git_vector *list,
-       git_attr_file_source source,
-       const char *base,
-       const char *filename,
+       git_attr_file_source *source,
        bool allow_macros)
 {
        int error = 0;
        git_attr_file *file = NULL;
 
        error = git_attr_cache__get(&file, repo, attr_session,
-               source, base, filename, git_attr_file__parse_buffer, allow_macros);
+                                   source,
+                                   git_attr_file__parse_buffer,
+                                   allow_macros);
 
        if (error < 0)
                return error;
@@ -468,20 +561,46 @@ static int push_attr_file(
        return error;
 }
 
+GIT_INLINE(int) push_attr_file(
+       git_repository *repo,
+       git_attr_session *attr_session,
+       git_vector *list,
+       const char *base,
+       const char *filename)
+{
+       git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE, base, filename };
+       return push_attr_source(repo, attr_session, list, &source, true);
+}
+
 static int push_one_attr(void *ref, const char *path)
 {
        attr_walk_up_info *info = (attr_walk_up_info *)ref;
-       git_attr_file_source src[GIT_ATTR_FILE_NUM_SOURCES];
+       git_attr_file_source_t src[GIT_ATTR_FILE_NUM_SOURCES];
        int error = 0, n_src, i;
        bool allow_macros;
 
-       n_src = attr_decide_sources(
-               info->flags, info->workdir != NULL, info->index != NULL, src);
+       n_src = attr_decide_sources(info->opts ? info->opts->flags : 0,
+                                   info->workdir != NULL,
+                                   info->index != NULL,
+                                   src);
+
        allow_macros = info->workdir ? !strcmp(info->workdir, path) : false;
 
-       for (i = 0; !error && i < n_src; ++i)
-               error = push_attr_file(info->repo, info->attr_session, info->files,
-                                      src[i], path, GIT_ATTR_FILE, allow_macros);
+       for (i = 0; !error && i < n_src; ++i) {
+               git_attr_file_source source = { src[i], path, GIT_ATTR_FILE };
+
+               if (src[i] == GIT_ATTR_FILE_SOURCE_COMMIT && info->opts) {
+#ifndef GIT_DEPRECATE_HARD
+                       if (info->opts->commit_id)
+                               source.commit_id = info->opts->commit_id;
+                       else
+#endif
+                       source.commit_id = &info->opts->attr_commit_id;
+               }
+
+               error = push_attr_source(info->repo, info->attr_session, info->files,
+                                      &source, allow_macros);
+       }
 
        return error;
 }
@@ -501,7 +620,7 @@ static void release_attr_files(git_vector *files)
 static int collect_attr_files(
        git_repository *repo,
        git_attr_session *attr_session,
-       uint32_t flags,
+       git_attr_options *opts,
        const char *path,
        git_vector *files)
 {
@@ -510,14 +629,20 @@ static int collect_attr_files(
        const char *workdir = git_repository_workdir(repo);
        attr_walk_up_info info = { NULL };
 
-       if ((error = attr_setup(repo, attr_session, flags)) < 0)
+       GIT_ASSERT(!git_path_is_absolute(path));
+
+       if ((error = attr_setup(repo, attr_session, opts)) < 0)
                return error;
 
        /* Resolve path in a non-bare repo */
-       if (workdir != NULL)
-               error = git_path_find_dir(&dir, path, workdir);
-       else
+       if (workdir != NULL) {
+               if (!(error = git_repository_workdir_path(&dir, repo, path)))
+                       error = git_path_find_dir(&dir);
+       }
+       else {
                error = git_path_dirname_r(&dir, path);
+       }
+
        if (error < 0)
                goto cleanup;
 
@@ -529,15 +654,14 @@ static int collect_attr_files(
         */
 
        if ((error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
-           (error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
-                                   attrfile.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) {
+           (error = push_attr_file(repo, attr_session, files, attrfile.ptr, GIT_ATTR_FILE_INREPO)) < 0) {
                if (error != GIT_ENOTFOUND)
                        goto cleanup;
        }
 
        info.repo = repo;
        info.attr_session = attr_session;
-       info.flags = flags;
+       info.opts = opts;
        info.workdir = workdir;
        if (git_repository_index__weakptr(&info.index, repo) < 0)
                git_error_clear(); /* no error even if there is no index */
@@ -552,18 +676,16 @@ static int collect_attr_files(
                goto cleanup;
 
        if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
-               error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
-                                      NULL, git_repository_attr_cache(repo)->cfg_attr_file, true);
+               error = push_attr_file(repo, attr_session, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file);
                if (error < 0)
                        goto cleanup;
        }
 
-       if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
+       if (!opts || (opts->flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
                error = system_attr_file(&dir, attr_session);
 
                if (!error)
-                       error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
-                                              NULL, dir.ptr, true);
+                       error = push_attr_file(repo, attr_session, files, NULL, dir.ptr);
                else if (error == GIT_ENOTFOUND)
                        error = 0;
        }
index 3f69b5ffcb3ebe9558aa8d033069bd2d8ad47366..71bd20a0f64104688e276f2b8f00f120328bb3ed 100644 (file)
@@ -10,7 +10,6 @@
 #include "repository.h"
 #include "filebuf.h"
 #include "attrcache.h"
-#include "buf_text.h"
 #include "git2/blob.h"
 #include "git2/tree.h"
 #include "blob.h"
@@ -34,7 +33,7 @@ static void attr_file_free(git_attr_file *file)
 int git_attr_file__new(
        git_attr_file **out,
        git_attr_file_entry *entry,
-       git_attr_file_source source)
+       git_attr_file_source *source)
 {
        git_attr_file *attrs = git__calloc(1, sizeof(git_attr_file));
        GIT_ERROR_CHECK_ALLOC(attrs);
@@ -48,8 +47,8 @@ int git_attr_file__new(
                goto on_error;
 
        GIT_REFCOUNT_INC(attrs);
-       attrs->entry  = entry;
-       attrs->source = source;
+       attrs->entry = entry;
+       memcpy(&attrs->source, source, sizeof(git_attr_file_source));
        *out = attrs;
        return 0;
 
@@ -109,11 +108,12 @@ int git_attr_file__load(
        git_repository *repo,
        git_attr_session *attr_session,
        git_attr_file_entry *entry,
-       git_attr_file_source source,
+       git_attr_file_source *source,
        git_attr_file_parser parser,
        bool allow_macros)
 {
        int error = 0;
+       git_commit *commit = NULL;
        git_tree *tree = NULL;
        git_tree_entry *tree_entry = NULL;
        git_blob *blob = NULL;
@@ -123,17 +123,17 @@ int git_attr_file__load(
        struct stat st;
        bool nonexistent = false;
        int bom_offset;
-       git_bom_t bom;
+       git_buf_bom_t bom;
        git_oid id;
        git_object_size_t blobsize;
 
        *out = NULL;
 
-       switch (source) {
-       case GIT_ATTR_FILE__IN_MEMORY:
+       switch (source->type) {
+       case GIT_ATTR_FILE_SOURCE_MEMORY:
                /* in-memory attribute file doesn't need data */
                break;
-       case GIT_ATTR_FILE__FROM_INDEX: {
+       case GIT_ATTR_FILE_SOURCE_INDEX: {
                if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
                        (error = git_blob_lookup(&blob, repo, &id)) < 0)
                        return error;
@@ -146,7 +146,7 @@ int git_attr_file__load(
                git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize);
                break;
        }
-       case GIT_ATTR_FILE__FROM_FILE: {
+       case GIT_ATTR_FILE_SOURCE_FILE: {
                int fd = -1;
 
                /* For open or read errors, pretend that we got ENOTFOUND. */
@@ -163,10 +163,32 @@ int git_attr_file__load(
 
                break;
        }
-       case GIT_ATTR_FILE__FROM_HEAD: {
-               if ((error = git_repository_head_tree(&tree, repo)) < 0 ||
-                   (error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0 ||
-                   (error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0)
+       case GIT_ATTR_FILE_SOURCE_HEAD:
+       case GIT_ATTR_FILE_SOURCE_COMMIT: {
+               if (source->type == GIT_ATTR_FILE_SOURCE_COMMIT) {
+                       if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0 ||
+                           (error = git_commit_tree(&tree, commit)) < 0)
+                               goto cleanup;
+               } else {
+                       if ((error = git_repository_head_tree(&tree, repo)) < 0)
+                               goto cleanup;
+               }
+
+               if ((error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0) {
+                       /*
+                        * If the attributes file does not exist, we can
+                        * cache an empty file for this commit to prevent
+                        * needless future lookups.
+                        */
+                       if (error == GIT_ENOTFOUND) {
+                               error = 0;
+                               break;
+                       }
+
+                       goto cleanup;
+               }
+
+               if ((error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0)
                        goto cleanup;
 
                /*
@@ -183,7 +205,7 @@ int git_attr_file__load(
                break;
        }
        default:
-               git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source);
+               git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source->type);
                return -1;
        }
 
@@ -192,9 +214,9 @@ int git_attr_file__load(
 
        /* advance over a UTF8 BOM */
        content_str = git_buf_cstr(&content);
-       bom_offset = git_buf_text_detect_bom(&bom, &content);
+       bom_offset = git_buf_detect_bom(&bom, &content);
 
-       if (bom == GIT_BOM_UTF8)
+       if (bom == GIT_BUF_BOM_UTF8)
                content_str += bom_offset;
 
        /* store the key of the attr_reader; don't bother with cache
@@ -211,11 +233,13 @@ int git_attr_file__load(
        /* write cache breakers */
        if (nonexistent)
                file->nonexistent = 1;
-       else if (source == GIT_ATTR_FILE__FROM_INDEX)
+       else if (source->type == GIT_ATTR_FILE_SOURCE_INDEX)
                git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
-       else if (source == GIT_ATTR_FILE__FROM_HEAD)
+       else if (source->type == GIT_ATTR_FILE_SOURCE_HEAD)
                git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
-       else if (source == GIT_ATTR_FILE__FROM_FILE)
+       else if (source->type == GIT_ATTR_FILE_SOURCE_COMMIT)
+               git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
+       else if (source->type == GIT_ATTR_FILE_SOURCE_FILE)
                git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
        /* else always cacheable */
 
@@ -225,6 +249,7 @@ cleanup:
        git_blob_free(blob);
        git_tree_entry_free(tree_entry);
        git_tree_free(tree);
+       git_commit_free(commit);
        git_buf_dispose(&content);
 
        return error;
@@ -233,7 +258,8 @@ cleanup:
 int git_attr_file__out_of_date(
        git_repository *repo,
        git_attr_session *attr_session,
-       git_attr_file *file)
+       git_attr_file *file,
+       git_attr_file_source *source)
 {
        if (!file)
                return 1;
@@ -246,15 +272,15 @@ int git_attr_file__out_of_date(
        else if (file->nonexistent)
                return 1;
 
-       switch (file->source) {
-       case GIT_ATTR_FILE__IN_MEMORY:
+       switch (file->source.type) {
+       case GIT_ATTR_FILE_SOURCE_MEMORY:
                return 0;
 
-       case GIT_ATTR_FILE__FROM_FILE:
+       case GIT_ATTR_FILE_SOURCE_FILE:
                return git_futils_filestamp_check(
                        &file->cache_data.stamp, file->entry->fullpath);
 
-       case GIT_ATTR_FILE__FROM_INDEX: {
+       case GIT_ATTR_FILE_SOURCE_INDEX: {
                int error;
                git_oid id;
 
@@ -265,21 +291,41 @@ int git_attr_file__out_of_date(
                return (git_oid__cmp(&file->cache_data.oid, &id) != 0);
        }
 
-       case GIT_ATTR_FILE__FROM_HEAD: {
-               git_tree *tree;
+       case GIT_ATTR_FILE_SOURCE_HEAD: {
+               git_tree *tree = NULL;
+               int error = git_repository_head_tree(&tree, repo);
+
+               if (error < 0)
+                       return error;
+
+               error = (git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)) != 0);
+
+               git_tree_free(tree);
+               return error;
+       }
+
+       case GIT_ATTR_FILE_SOURCE_COMMIT: {
+               git_commit *commit = NULL;
+               git_tree *tree = NULL;
                int error;
 
-               if ((error = git_repository_head_tree(&tree, repo)) < 0)
+               if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0)
+                       return error;
+
+               error = git_commit_tree(&tree, commit);
+               git_commit_free(commit);
+
+               if (error < 0)
                        return error;
 
-               error = git_oid__cmp(&file->cache_data.oid, git_tree_id(tree));
+               error = (git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)) != 0);
 
                git_tree_free(tree);
                return error;
        }
 
        default:
-               git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source);
+               git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source.type);
                return -1;
        }
 }
@@ -351,7 +397,9 @@ uint32_t git_attr_file__name_hash(const char *name)
 {
        uint32_t h = 5381;
        int c;
-       assert(name);
+
+       GIT_ASSERT_ARG(name);
+
        while ((c = (int)*name++) != 0)
                h = ((h << 5) + h) + c;
        return h;
@@ -388,6 +436,7 @@ int git_attr_file__lookup_one(
 int git_attr_file__load_standalone(git_attr_file **out, const char *path)
 {
        git_buf content = GIT_BUF_INIT;
+       git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE };
        git_attr_file *file = NULL;
        int error;
 
@@ -399,9 +448,9 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path)
         * don't have to free it - freeing file+pool will free cache entry, too.
         */
 
-       if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 ||
+       if ((error = git_attr_file__new(&file, NULL, &source)) < 0 ||
            (error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 ||
-           (error = git_attr_cache__alloc_file_entry(&file->entry, NULL, path, &file->pool)) < 0)
+           (error = git_attr_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0)
                goto out;
 
        *out = file;
@@ -501,7 +550,10 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
 }
 
 int git_attr_path__init(
-       git_attr_path *info, const char *path, const char *base, git_dir_flag dir_flag)
+       git_attr_path *info,
+       const char *path,
+       const char *base,
+       git_dir_flag dir_flag)
 {
        ssize_t root;
 
@@ -660,7 +712,8 @@ int git_attr_fnmatch__parse(
        int slash_count, allow_space;
        bool escaped;
 
-       assert(spec && base && *base);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(base && *base);
 
        if (parse_optimized_patterns(spec, pool, *base))
                return 0;
@@ -828,7 +881,7 @@ int git_attr_assignment__parse(
        const char *scan = *base;
        git_attr_assignment *assign = NULL;
 
-       assert(assigns && !assigns->length);
+       GIT_ASSERT_ARG(assigns && !assigns->length);
 
        git_vector_set_cmp(assigns, sort_by_hash_and_name);
 
@@ -954,10 +1007,10 @@ void git_attr_rule__free(git_attr_rule *rule)
 
 int git_attr_session__init(git_attr_session *session, git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        memset(session, 0, sizeof(*session));
-       session->key = git_atomic_inc(&repo->attr_session_key);
+       session->key = git_atomic32_inc(&repo->attr_session_key);
 
        return 0;
 }
index 2b6b1d6232aa869e6e65cb6b119725f15fa8f257..d634e6da948498731f8534711ca30338a2df645e 100644 (file)
        (GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
 
 typedef enum {
-       GIT_ATTR_FILE__IN_MEMORY   = 0,
-       GIT_ATTR_FILE__FROM_FILE   = 1,
-       GIT_ATTR_FILE__FROM_INDEX  = 2,
-       GIT_ATTR_FILE__FROM_HEAD   = 3,
+       GIT_ATTR_FILE_SOURCE_MEMORY = 0,
+       GIT_ATTR_FILE_SOURCE_FILE   = 1,
+       GIT_ATTR_FILE_SOURCE_INDEX  = 2,
+       GIT_ATTR_FILE_SOURCE_HEAD   = 3,
+       GIT_ATTR_FILE_SOURCE_COMMIT = 4,
 
-       GIT_ATTR_FILE_NUM_SOURCES  = 4
+       GIT_ATTR_FILE_NUM_SOURCES   = 5
+} git_attr_file_source_t;
+
+typedef struct {
+       /* The source location for the attribute file. */
+       git_attr_file_source_t type;
+
+       /*
+        * The filename of the attribute file to read (relative to the
+        * given base path).
+        */
+       const char *base;
+       const char *filename;
+
+       /*
+        * The commit ID when the given source type is a commit (or NULL
+        * for the repository's HEAD commit.)
+        */
+       git_oid *commit_id;
 } git_attr_file_source;
 
 extern const char *git_attr__true;
@@ -124,7 +143,7 @@ extern int git_attr_get_many_with_session(
        const char **values_out,
        git_repository *repo,
        git_attr_session *attr_session,
-       uint32_t flags,
+       git_attr_options *opts,
        const char *path,
        size_t num_attr,
        const char **names);
@@ -142,7 +161,7 @@ typedef int (*git_attr_file_parser)(
 int git_attr_file__new(
        git_attr_file **out,
        git_attr_file_entry *entry,
-       git_attr_file_source source);
+       git_attr_file_source *source);
 
 void git_attr_file__free(git_attr_file *file);
 
@@ -151,7 +170,7 @@ int git_attr_file__load(
        git_repository *repo,
        git_attr_session *attr_session,
        git_attr_file_entry *ce,
-       git_attr_file_source source,
+       git_attr_file_source *source,
        git_attr_file_parser parser,
        bool allow_macros);
 
@@ -159,7 +178,7 @@ int git_attr_file__load_standalone(
        git_attr_file **out, const char *path);
 
 int git_attr_file__out_of_date(
-       git_repository *repo, git_attr_session *session, git_attr_file *file);
+       git_repository *repo, git_attr_session *session, git_attr_file *file, git_attr_file_source *source);
 
 int git_attr_file__parse_buffer(
        git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros);
@@ -207,8 +226,10 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment(
 typedef enum { GIT_DIR_FLAG_TRUE = 1, GIT_DIR_FLAG_FALSE = 0, GIT_DIR_FLAG_UNKNOWN = -1 } git_dir_flag;
 
 extern int git_attr_path__init(
-       git_attr_path *info, const char *path, const char *base, git_dir_flag is_dir);
-
+       git_attr_path *out,
+       const char *path,
+       const char *base,
+       git_dir_flag is_dir);
 extern void git_attr_path__free(git_attr_path *info);
 
 extern int git_attr_assignment__parse(
index 47fb675e057932c06cfd8a39c4fb4a58487cb485..2b36b7a9c98d2aac755f54fc39c2e7039be8b3ff 100644 (file)
@@ -38,6 +38,7 @@ GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
 
 int git_attr_cache__alloc_file_entry(
        git_attr_file_entry **out,
+       git_repository *repo,
        const char *base,
        const char *path,
        git_pool *pool)
@@ -65,6 +66,9 @@ int git_attr_cache__alloc_file_entry(
        }
        memcpy(&ce->fullpath[baselen], path, pathlen);
 
+       if (git_path_validate_workdir_with_len(repo, ce->fullpath, pathlen + baselen) < 0)
+               return -1;
+
        ce->path = &ce->fullpath[baselen];
        *out = ce;
 
@@ -79,8 +83,8 @@ static int attr_cache_make_entry(
        git_attr_file_entry *entry = NULL;
        int error;
 
-       if ((error = git_attr_cache__alloc_file_entry(&entry, git_repository_workdir(repo),
-                                                     path, &cache->pool)) < 0)
+       if ((error = git_attr_cache__alloc_file_entry(&entry, repo,
+               git_repository_workdir(repo), path, &cache->pool)) < 0)
                return error;
 
        if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
@@ -108,7 +112,7 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
         * Replace the existing value if another thread has
         * created it in the meantime.
         */
-       old = git__swap(entry->file[file->source], file);
+       old = git_atomic_swap(entry->file[file->source.type], file);
 
        if (old) {
                GIT_REFCOUNT_OWN(old, NULL);
@@ -123,7 +127,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
 {
        int error = 0;
        git_attr_file_entry *entry;
-       git_attr_file *old = NULL;
+       git_attr_file *oldfile = NULL;
 
        if (!file)
                return 0;
@@ -132,13 +136,13 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
                return error;
 
        if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
-               old = git__compare_and_swap(&entry->file[file->source], file, NULL);
+               oldfile = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
 
        attr_cache_unlock(cache);
 
-       if (old) {
-               GIT_REFCOUNT_OWN(old, NULL);
-               git_attr_file__free(old);
+       if (oldfile == file) {
+               GIT_REFCOUNT_OWN(file, NULL);
+               git_attr_file__free(file);
        }
 
        return error;
@@ -154,40 +158,42 @@ static int attr_cache_lookup(
        git_attr_file_entry **out_entry,
        git_repository *repo,
        git_attr_session *attr_session,
-       git_attr_file_source source,
-       const char *base,
-       const char *filename)
+       git_attr_file_source *source)
 {
        int error = 0;
        git_buf path = GIT_BUF_INIT;
-       const char *wd = git_repository_workdir(repo), *relfile;
+       const char *wd = git_repository_workdir(repo);
+       const char *filename;
        git_attr_cache *cache = git_repository_attr_cache(repo);
        git_attr_file_entry *entry = NULL;
        git_attr_file *file = NULL;
 
        /* join base and path as needed */
-       if (base != NULL && git_path_root(filename) < 0) {
+       if (source->base != NULL && git_path_root(source->filename) < 0) {
                git_buf *p = attr_session ? &attr_session->tmp : &path;
 
-               if (git_buf_joinpath(p, base, filename) < 0)
+               if (git_buf_joinpath(p, source->base, source->filename) < 0 ||
+                   git_path_validate_workdir_buf(repo, p) < 0)
                        return -1;
 
                filename = p->ptr;
+       } else {
+               filename = source->filename;
        }
 
-       relfile = filename;
-       if (wd && !git__prefixcmp(relfile, wd))
-               relfile += strlen(wd);
+       if (wd && !git__prefixcmp(filename, wd))
+               filename += strlen(wd);
 
        /* check cache for existing entry */
        if ((error = attr_cache_lock(cache)) < 0)
                goto cleanup;
 
-       entry = attr_cache_lookup_entry(cache, relfile);
-       if (!entry)
-               error = attr_cache_make_entry(&entry, repo, relfile);
-       else if (entry->file[source] != NULL) {
-               file = entry->file[source];
+       entry = attr_cache_lookup_entry(cache, filename);
+
+       if (!entry) {
+               error = attr_cache_make_entry(&entry, repo, filename);
+       } else if (entry->file[source->type] != NULL) {
+               file = entry->file[source->type];
                GIT_REFCOUNT_INC(file);
        }
 
@@ -205,9 +211,7 @@ int git_attr_cache__get(
        git_attr_file **out,
        git_repository *repo,
        git_attr_session *attr_session,
-       git_attr_file_source source,
-       const char *base,
-       const char *filename,
+       git_attr_file_source *source,
        git_attr_file_parser parser,
        bool allow_macros)
 {
@@ -216,19 +220,21 @@ int git_attr_cache__get(
        git_attr_file_entry *entry = NULL;
        git_attr_file *file = NULL, *updated = NULL;
 
-       if ((error = attr_cache_lookup(
-                       &file, &entry, repo, attr_session, source, base, filename)) < 0)
+       if ((error = attr_cache_lookup(&file, &entry, repo, attr_session, source)) < 0)
                return error;
 
        /* load file if we don't have one or if existing one is out of date */
-       if (!file || (error = git_attr_file__out_of_date(repo, attr_session, file)) > 0)
-               error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser, allow_macros);
+       if (!file ||
+           (error = git_attr_file__out_of_date(repo, attr_session, file, source)) > 0)
+               error = git_attr_file__load(&updated, repo, attr_session,
+                                           entry, source, parser,
+                                           allow_macros);
 
        /* if we loaded the file, insert into and/or update cache */
        if (updated) {
-               if ((error = attr_cache_upsert(cache, updated)) < 0)
+               if ((error = attr_cache_upsert(cache, updated)) < 0) {
                        git_attr_file__free(updated);
-               else {
+               else {
                        git_attr_file__free(file); /* offset incref from lookup */
                        file = updated;
                }
@@ -255,7 +261,7 @@ int git_attr_cache__get(
 
 bool git_attr_cache__is_cached(
        git_repository *repo,
-       git_attr_file_source source,
+       git_attr_file_source_t source_type,
        const char *filename)
 {
        git_attr_cache *cache = git_repository_attr_cache(repo);
@@ -268,7 +274,7 @@ bool git_attr_cache__is_cached(
        if ((entry = git_strmap_get(files, filename)) == NULL)
                return false;
 
-       return entry && (entry->file[source] != NULL);
+       return entry && (entry->file[source_type] != NULL);
 }
 
 
@@ -321,7 +327,7 @@ static void attr_cache__free(git_attr_cache *cache)
 
                git_strmap_foreach_value(cache->files, entry, {
                        for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
-                               if ((file = git__swap(entry->file[i], NULL)) != NULL) {
+                               if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) {
                                        GIT_REFCOUNT_OWN(file, NULL);
                                        git_attr_file__free(file);
                                }
@@ -395,8 +401,7 @@ int git_attr_cache__init(git_repository *repo)
            (ret = git_pool_init(&cache->pool, 1)) < 0)
                goto cancel;
 
-       cache = git__compare_and_swap(&repo->attrcache, NULL, cache);
-       if (cache)
+       if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL)
                goto cancel; /* raced with another thread, free this but no error */
 
        git_config_free(cfg);
@@ -417,7 +422,7 @@ int git_attr_cache_flush(git_repository *repo)
        /* this could be done less expensively, but for now, we'll just free
         * the entire attrcache and let the next use reinitialize it...
         */
-       if (repo && (cache = git__swap(repo->attrcache, NULL)) != NULL)
+       if (repo && (cache = git_atomic_swap(repo->attrcache, NULL)) != NULL)
                attr_cache__free(cache);
 
        return 0;
index 4b1d5ce312b6a00e0b362c80352d4cdbd983e6e3..b13e0e8f0a819a8a1103222828bc142e464e149c 100644 (file)
@@ -31,19 +31,18 @@ extern int git_attr_cache__get(
        git_attr_file **file,
        git_repository *repo,
        git_attr_session *attr_session,
-       git_attr_file_source source,
-       const char *base,
-       const char *filename,
+       git_attr_file_source *source,
        git_attr_file_parser parser,
        bool allow_macros);
 
 extern bool git_attr_cache__is_cached(
        git_repository *repo,
-       git_attr_file_source source,
-       const char *path);
+       git_attr_file_source_t source_type,
+       const char *filename);
 
 extern int git_attr_cache__alloc_file_entry(
        git_attr_file_entry **out,
+       git_repository *repo,
        const char *base,
        const char *path,
        git_pool *pool);
index 1046dab55e2fc9c648633cfead705cab02081b21..a6ab43efd8f83aa7dc26463048f81af9d6b29e4c 100644 (file)
@@ -59,7 +59,7 @@ static bool hunk_starts_at_or_after_line(git_blame_hunk *hunk, size_t line)
        return line <= hunk->final_start_line_number;
 }
 
-static git_blame_hunknew_hunk(
+static git_blame_hunk *new_hunk(
                size_t start,
                size_t lines,
                size_t orig_start,
@@ -76,7 +76,15 @@ static git_blame_hunk* new_hunk(
        return hunk;
 }
 
-static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
+static void free_hunk(git_blame_hunk *hunk)
+{
+       git__free((void*)hunk->orig_path);
+       git_signature_free(hunk->final_signature);
+       git_signature_free(hunk->orig_signature);
+       git__free(hunk);
+}
+
+static git_blame_hunk *dup_hunk(git_blame_hunk *hunk)
 {
        git_blame_hunk *newhunk = new_hunk(
                        hunk->final_start_line_number,
@@ -90,17 +98,14 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
        git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id);
        git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id);
        newhunk->boundary = hunk->boundary;
-       git_signature_dup(&newhunk->final_signature, hunk->final_signature);
-       git_signature_dup(&newhunk->orig_signature, hunk->orig_signature);
-       return newhunk;
-}
 
-static void free_hunk(git_blame_hunk *hunk)
-{
-       git__free((void*)hunk->orig_path);
-       git_signature_free(hunk->final_signature);
-       git_signature_free(hunk->orig_signature);
-       git__free(hunk);
+       if (git_signature_dup(&newhunk->final_signature, hunk->final_signature) < 0 ||
+               git_signature_dup(&newhunk->orig_signature, hunk->orig_signature) < 0) {
+               free_hunk(newhunk);
+               return NULL;
+       }
+
+       return newhunk;
 }
 
 /* Starting with the hunk that includes start_line, shift all following hunks'
@@ -117,7 +122,7 @@ static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by)
        }
 }
 
-git_blamegit_blame__alloc(
+git_blame *git_blame__alloc(
        git_repository *repo,
        git_blame_options opts,
        const char *path)
@@ -171,20 +176,21 @@ void git_blame_free(git_blame *blame)
 
 uint32_t git_blame_get_hunk_count(git_blame *blame)
 {
-       assert(blame);
+       GIT_ASSERT_ARG(blame);
        return (uint32_t)blame->hunks.length;
 }
 
 const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t index)
 {
-       assert(blame);
+       GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL);
        return (git_blame_hunk*)git_vector_get(&blame->hunks, index);
 }
 
 const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno)
 {
        size_t i, new_lineno = lineno;
-       assert(blame);
+
+       GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL);
 
        if (!git_vector_bsearch2(&i, &blame->hunks, hunk_byfinalline_search_cmp, &new_lineno)) {
                return git_blame_get_hunk_byindex(blame, (uint32_t)i);
@@ -293,7 +299,7 @@ static int index_blob_lines(git_blame *blame)
     return blame->num_lines;
 }
 
-static git_blame_hunkhunk_from_entry(git_blame__entry *e, git_blame *blame)
+static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame)
 {
        git_blame_hunk *h = new_hunk(
                        e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path);
@@ -388,7 +394,10 @@ int git_blame_file(
        git_blame_options normOptions = GIT_BLAME_OPTIONS_INIT;
        git_blame *blame = NULL;
 
-       assert(out && repo && path);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(path);
+
        if ((error = normalize_options(&normOptions, options, repo)) < 0)
                goto on_error;
 
@@ -509,7 +518,9 @@ int git_blame_buffer(
 
        diffopts.context_lines = 0;
 
-       assert(out && reference && buffer && buffer_len);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(reference);
+       GIT_ASSERT_ARG(buffer && buffer_len);
 
        blame = git_blame__alloc(reference->repository, reference->options, reference->path);
        GIT_ERROR_CHECK_ALLOC(blame);
index 073137a68a151ee39c34ef54fede4d0516920162..3d514a1bc0f4de760db084d5e4a08d9d08898e36 100644 (file)
@@ -429,7 +429,7 @@ static int paths_on_dup(void **old, void *new)
        return -1;
 }
 
-static git_blame__originfind_origin(
+static git_blame__origin *find_origin(
                git_blame *blame,
                git_commit *parent,
                git_blame__origin *origin)
index da4e6ffa5442672ba3dacad0acd6ad7120d6e36e..09b5b5d9121a300fad5bf82aa6a6e701001063f1 100644 (file)
 
 #include "filebuf.h"
 #include "filter.h"
-#include "buf_text.h"
 
 const void *git_blob_rawcontent(const git_blob *blob)
 {
-       assert(blob);
+       GIT_ASSERT_ARG_WITH_RETVAL(blob, NULL);
+
        if (blob->raw)
                return blob->data.raw.data;
        else
@@ -27,7 +27,8 @@ const void *git_blob_rawcontent(const git_blob *blob)
 
 git_object_size_t git_blob_rawsize(const git_blob *blob)
 {
-       assert(blob);
+       GIT_ASSERT_ARG(blob);
+
        if (blob->raw)
                return blob->data.raw.size;
        else
@@ -53,7 +54,9 @@ void git_blob__free(void *_blob)
 int git_blob__parse_raw(void *_blob, const char *data, size_t size)
 {
        git_blob *blob = (git_blob *) _blob;
-       assert(blob);
+
+       GIT_ASSERT_ARG(blob);
+
        blob->raw = 1;
        blob->data.raw.data = data;
        blob->data.raw.size = size;
@@ -63,7 +66,9 @@ int git_blob__parse_raw(void *_blob, const char *data, size_t size)
 int git_blob__parse(void *_blob, git_odb_object *odb_obj)
 {
        git_blob *blob = (git_blob *) _blob;
-       assert(blob);
+
+       GIT_ASSERT_ARG(blob);
+
        git_cached_obj_incref((git_cached_obj *)odb_obj);
        blob->raw = 0;
        blob->data.odb = odb_obj;
@@ -77,7 +82,8 @@ int git_blob_create_from_buffer(
        git_odb *odb;
        git_odb_stream *stream;
 
-       assert(id && repo);
+       GIT_ASSERT_ARG(id);
+       GIT_ASSERT_ARG(repo);
 
        if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
                (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJECT_BLOB)) < 0)
@@ -132,12 +138,13 @@ static int write_file_filtered(
        git_object_size_t *size,
        git_odb *odb,
        const char *full_path,
-       git_filter_list *fl)
+       git_filter_list *fl,
+       git_repository* repo)
 {
        int error;
        git_buf tgt = GIT_BUF_INIT;
 
-       error = git_filter_list_apply_to_file(&tgt, fl, NULL, full_path);
+       error = git_filter_list_apply_to_file(&tgt, fl, repo, full_path);
 
        /* Write the file to disk if it was properly filtered */
        if (!error) {
@@ -188,14 +195,10 @@ int git_blob__create_from_paths(
        mode_t mode;
        git_buf path = GIT_BUF_INIT;
 
-       assert(hint_path || !try_load_filters);
+       GIT_ASSERT_ARG(hint_path || !try_load_filters);
 
        if (!content_path) {
-               if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
-                       return GIT_EBAREREPO;
-
-               if (git_buf_joinpath(
-                               &path, git_repository_workdir(repo), hint_path) < 0)
+               if (git_repository_workdir_path(&path, repo, hint_path) < 0)
                        return -1;
 
                content_path = path.ptr;
@@ -236,7 +239,7 @@ int git_blob__create_from_paths(
                        error = write_file_stream(id, odb, content_path, size);
                else {
                        /* We need to apply one or more filters */
-                       error = write_file_filtered(id, &size, odb, content_path, fl);
+                       error = write_file_filtered(id, &size, odb, content_path, fl, repo);
 
                        git_filter_list_free(fl);
                }
@@ -274,21 +277,20 @@ int git_blob_create_from_disk(
 {
        int error;
        git_buf full_path = GIT_BUF_INIT;
-       const char *workdir, *hintpath;
+       const char *workdir, *hintpath = NULL;
 
        if ((error = git_path_prettify(&full_path, path, NULL)) < 0) {
                git_buf_dispose(&full_path);
                return error;
        }
 
-       hintpath = git_buf_cstr(&full_path);
        workdir  = git_repository_workdir(repo);
 
-       if (workdir && !git__prefixcmp(hintpath, workdir))
-               hintpath += strlen(workdir);
+       if (workdir && !git__prefixcmp(full_path.ptr, workdir))
+               hintpath = full_path.ptr + strlen(workdir);
 
        error = git_blob__create_from_paths(
-               id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true);
+               id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, !!hintpath);
 
        git_buf_dispose(&full_path);
        return error;
@@ -331,7 +333,8 @@ int git_blob_create_from_stream(git_writestream **out, git_repository *repo, con
        git_buf path = GIT_BUF_INIT;
        blob_writestream *stream;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        stream = git__calloc(1, sizeof(blob_writestream));
        GIT_ERROR_CHECK_ALLOC(stream);
@@ -391,13 +394,22 @@ int git_blob_is_binary(const git_blob *blob)
        git_buf content = GIT_BUF_INIT;
        git_object_size_t size;
 
-       assert(blob);
+       GIT_ASSERT_ARG(blob);
 
        size = git_blob_rawsize(blob);
 
        git_buf_attach_notowned(&content, git_blob_rawcontent(blob),
                (size_t)min(size, GIT_FILTER_BYTES_TO_CHECK_NUL));
-       return git_buf_text_is_binary(&content);
+       return git_buf_is_binary(&content);
+}
+
+int git_blob_filter_options_init(
+       git_blob_filter_options *opts,
+       unsigned int version)
+{
+       GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
+               git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_INIT);
+       return 0;
 }
 
 int git_blob_filter(
@@ -409,15 +421,18 @@ int git_blob_filter(
        int error = 0;
        git_filter_list *fl = NULL;
        git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
-       git_filter_flag_t flags = GIT_FILTER_DEFAULT;
-
-       assert(blob && path && out);
+       git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
 
-       git_buf_sanitize(out);
+       GIT_ASSERT_ARG(blob);
+       GIT_ASSERT_ARG(path);
+       GIT_ASSERT_ARG(out);
 
        GIT_ERROR_CHECK_VERSION(
                given_opts, GIT_BLOB_FILTER_OPTIONS_VERSION, "git_blob_filter_options");
 
+       if (git_buf_sanitize(out) < 0)
+               return -1;
+
        if (given_opts != NULL)
                memcpy(&opts, given_opts, sizeof(git_blob_filter_options));
 
@@ -426,14 +441,25 @@ int git_blob_filter(
                return 0;
 
        if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
-               flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
+               filter_opts.flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
+
+       if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
+               filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
 
-       if ((opts.flags & GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD) != 0)
-               flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
+       if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
+               filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_COMMIT;
+
+#ifndef GIT_DEPRECATE_HARD
+               if (opts.commit_id)
+                       git_oid_cpy(&filter_opts.attr_commit_id, opts.commit_id);
+               else
+#endif
+               git_oid_cpy(&filter_opts.attr_commit_id, &opts.attr_commit_id);
+       }
 
-       if (!(error = git_filter_list_load(
+       if (!(error = git_filter_list_load_ext(
                        &fl, git_blob_owner(blob), blob, path,
-                       GIT_FILTER_TO_WORKTREE, flags))) {
+                       GIT_FILTER_TO_WORKTREE, &filter_opts))) {
 
                error = git_filter_list_apply_to_blob(out, fl, blob);
 
index 715f6cf99c70efa94c87f4cd670afe6fb87fc93a..e6818a86df5ba162c08a7947348f5629f03a7fa4 100644 (file)
@@ -67,8 +67,10 @@ static int create_branch(
        int error = -1;
        int bare = git_repository_is_bare(repository);
 
-       assert(branch_name && commit && ref_out);
-       assert(git_object_owner((const git_object *)commit) == repository);
+       GIT_ASSERT_ARG(branch_name);
+       GIT_ASSERT_ARG(commit);
+       GIT_ASSERT_ARG(ref_out);
+       GIT_ASSERT_ARG(git_commit_owner(commit) == repository);
 
        if (!git__strcmp(branch_name, "HEAD")) {
                git_error_set(GIT_ERROR_REFERENCE, "'HEAD' is not a valid branch name");
@@ -161,6 +163,8 @@ out:
 
 int git_branch_is_checked_out(const git_reference *branch)
 {
+       GIT_ASSERT_ARG(branch);
+
        if (!git_reference_is_branch(branch))
                return 0;
        return git_repository_foreach_worktree(git_reference_owner(branch),
@@ -173,7 +177,7 @@ int git_branch_delete(git_reference *branch)
        git_buf config_section = GIT_BUF_INIT;
        int error = -1;
 
-       assert(branch);
+       GIT_ASSERT_ARG(branch);
 
        if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
                git_error_set(GIT_ERROR_INVALID, "reference '%s' is not a valid branch.",
@@ -288,7 +292,8 @@ int git_branch_move(
                log_message = GIT_BUF_INIT;
        int error;
 
-       assert(branch && new_branch_name);
+       GIT_ASSERT_ARG(branch);
+       GIT_ASSERT_ARG(new_branch_name);
 
        if (!git_reference_is_branch(branch))
                return not_a_local_branch(git_reference_name(branch));
@@ -333,7 +338,10 @@ int git_branch_lookup(
        git_branch_t branch_type)
 {
        int error = -1;
-       assert(ref_out && repo && branch_name);
+
+       GIT_ASSERT_ARG(ref_out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(branch_name);
 
        switch (branch_type) {
        case GIT_BRANCH_LOCAL:
@@ -346,7 +354,7 @@ int git_branch_lookup(
                        error = retrieve_branch_reference(ref_out, repo, branch_name, true);
                break;
        default:
-               assert(false);
+               GIT_ASSERT(false);
        }
        return error;
 }
@@ -357,7 +365,8 @@ int git_branch_name(
 {
        const char *branch_name;
 
-       assert(out && ref);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ref);
 
        branch_name = ref->name;
 
@@ -405,9 +414,11 @@ int git_branch_upstream_name(
        const git_refspec *refspec;
        git_config *config;
 
-       assert(out && refname);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(refname);
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        if (!git_reference__is_branch(refname))
                return not_a_local_branch(refname);
@@ -457,7 +468,7 @@ cleanup:
        return error;
 }
 
-int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *refname)
+static int git_branch_upstream_with_format(git_buf *buf, git_repository *repo, const char *refname, const char *format, const char *format_name)
 {
        int error;
        git_config *cfg;
@@ -468,13 +479,12 @@ int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *r
        if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
                return error;
 
-       git_buf_sanitize(buf);
-
-       if ((error = retrieve_upstream_configuration(buf, cfg, refname, "branch.%s.remote")) < 0)
+       if ((error = git_buf_sanitize(buf)) < 0 ||
+           (error = retrieve_upstream_configuration(buf, cfg, refname, format)) < 0)
                return error;
 
        if (git_buf_len(buf) == 0) {
-               git_error_set(GIT_ERROR_REFERENCE, "branch '%s' does not have an upstream remote", refname);
+               git_error_set(GIT_ERROR_REFERENCE, "branch '%s' does not have an upstream %s", refname, format_name);
                error = GIT_ENOTFOUND;
                git_buf_clear(buf);
        }
@@ -482,6 +492,16 @@ int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *r
        return error;
 }
 
+int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *refname)
+{
+       return git_branch_upstream_with_format(buf, repo, refname, "branch.%s.remote", "remote");
+}
+
+int git_branch_upstream_merge(git_buf *buf, git_repository *repo, const char *refname)
+{
+       return git_branch_upstream_with_format(buf, repo, refname, "branch.%s.merge", "merge");
+}
+
 int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname)
 {
        git_strarray remote_list = {0};
@@ -491,9 +511,12 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna
        int error = 0;
        char *remote_name = NULL;
 
-       assert(buf && repo && refname);
+       GIT_ASSERT_ARG(buf);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(refname);
 
-       git_buf_sanitize(buf);
+       if ((error = git_buf_sanitize(buf)) < 0)
+               return error;
 
        /* Verify that this is a remote branch */
        if (!git_reference__is_remote(refname)) {
@@ -702,7 +725,7 @@ int git_branch_is_head(
        bool is_same = false;
        int error;
 
-       assert(branch);
+       GIT_ASSERT_ARG(branch);
 
        if (!git_reference_is_branch(branch))
                return false;
@@ -723,3 +746,32 @@ int git_branch_is_head(
 
        return is_same;
 }
+
+int git_branch_name_is_valid(int *valid, const char *name)
+{
+       git_buf ref_name = GIT_BUF_INIT;
+       int error = 0;
+
+       GIT_ASSERT(valid);
+
+       *valid = 0;
+
+       /*
+        * Discourage branch name starting with dash,
+        * https://github.com/git/git/commit/6348624010888b
+        * and discourage HEAD as branch name,
+        * https://github.com/git/git/commit/a625b092cc5994
+        */
+       if (!name || name[0] == '-' || !git__strcmp(name, "HEAD"))
+               goto done;
+
+       if ((error = git_buf_puts(&ref_name, GIT_REFS_HEADS_DIR)) < 0 ||
+           (error = git_buf_puts(&ref_name, name)) < 0)
+               goto done;
+
+       error = git_reference_name_is_valid(valid, ref_name.ptr);
+
+done:
+       git_buf_dispose(&ref_name);
+       return error;
+}
diff --git a/src/buf_text.c b/src/buf_text.c
deleted file mode 100644 (file)
index 88fcb87..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#include "buf_text.h"
-
-int git_buf_text_puts_escaped(
-       git_buf *buf,
-       const char *string,
-       const char *esc_chars,
-       const char *esc_with)
-{
-       const char *scan;
-       size_t total = 0, esc_len = strlen(esc_with), count, alloclen;
-
-       if (!string)
-               return 0;
-
-       for (scan = string; *scan; ) {
-               /* count run of non-escaped characters */
-               count = strcspn(scan, esc_chars);
-               total += count;
-               scan += count;
-               /* count run of escaped characters */
-               count = strspn(scan, esc_chars);
-               total += count * (esc_len + 1);
-               scan += count;
-       }
-
-       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, total, 1);
-       if (git_buf_grow_by(buf, alloclen) < 0)
-               return -1;
-
-       for (scan = string; *scan; ) {
-               count = strcspn(scan, esc_chars);
-
-               memmove(buf->ptr + buf->size, scan, count);
-               scan += count;
-               buf->size += count;
-
-               for (count = strspn(scan, esc_chars); count > 0; --count) {
-                       /* copy escape sequence */
-                       memmove(buf->ptr + buf->size, esc_with, esc_len);
-                       buf->size += esc_len;
-                       /* copy character to be escaped */
-                       buf->ptr[buf->size] = *scan;
-                       buf->size++;
-                       scan++;
-               }
-       }
-
-       buf->ptr[buf->size] = '\0';
-
-       return 0;
-}
-
-void git_buf_text_unescape(git_buf *buf)
-{
-       buf->size = git__unescape(buf->ptr);
-}
-
-int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
-{
-       const char *scan = src->ptr;
-       const char *scan_end = src->ptr + src->size;
-       const char *next = memchr(scan, '\r', src->size);
-       size_t new_size;
-       char *out;
-
-       assert(tgt != src);
-
-       if (!next)
-               return git_buf_set(tgt, src->ptr, src->size);
-
-       /* reduce reallocs while in the loop */
-       GIT_ERROR_CHECK_ALLOC_ADD(&new_size, src->size, 1);
-       if (git_buf_grow(tgt, new_size) < 0)
-               return -1;
-
-       out = tgt->ptr;
-       tgt->size = 0;
-
-       /* Find the next \r and copy whole chunk up to there to tgt */
-       for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) {
-               if (next > scan) {
-                       size_t copylen = (size_t)(next - scan);
-                       memcpy(out, scan, copylen);
-                       out += copylen;
-               }
-
-               /* Do not drop \r unless it is followed by \n */
-               if (next + 1 == scan_end || next[1] != '\n')
-                       *out++ = '\r';
-       }
-
-       /* Copy remaining input into dest */
-       if (scan < scan_end) {
-               size_t remaining = (size_t)(scan_end - scan);
-               memcpy(out, scan, remaining);
-               out += remaining;
-       }
-
-       tgt->size = (size_t)(out - tgt->ptr);
-       tgt->ptr[tgt->size] = '\0';
-
-       return 0;
-}
-
-int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
-{
-       const char *start = src->ptr;
-       const char *end = start + src->size;
-       const char *scan = start;
-       const char *next = memchr(scan, '\n', src->size);
-       size_t alloclen;
-
-       assert(tgt != src);
-
-       if (!next)
-               return git_buf_set(tgt, src->ptr, src->size);
-
-       /* attempt to reduce reallocs while in the loop */
-       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, src->size, src->size >> 4);
-       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
-       if (git_buf_grow(tgt, alloclen) < 0)
-               return -1;
-       tgt->size = 0;
-
-       for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
-               size_t copylen = next - scan;
-
-               /* if we find mixed line endings, carry on */
-               if (copylen && next[-1] == '\r')
-                       copylen--;
-
-               GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, copylen, 3);
-               if (git_buf_grow_by(tgt, alloclen) < 0)
-                       return -1;
-
-               if (copylen) {
-                       memcpy(tgt->ptr + tgt->size, scan, copylen);
-                       tgt->size += copylen;
-               }
-
-               tgt->ptr[tgt->size++] = '\r';
-               tgt->ptr[tgt->size++] = '\n';
-       }
-
-       tgt->ptr[tgt->size] = '\0';
-       return git_buf_put(tgt, scan, end - scan);
-}
-
-int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strings)
-{
-       size_t i;
-       const char *str, *pfx;
-
-       git_buf_clear(buf);
-
-       if (!strings || !strings->count)
-               return 0;
-
-       /* initialize common prefix to first string */
-       if (git_buf_sets(buf, strings->strings[0]) < 0)
-               return -1;
-
-       /* go through the rest of the strings, truncating to shared prefix */
-       for (i = 1; i < strings->count; ++i) {
-
-               for (str = strings->strings[i], pfx = buf->ptr;
-                        *str && *str == *pfx; str++, pfx++)
-                       /* scanning */;
-
-               git_buf_truncate(buf, pfx - buf->ptr);
-
-               if (!buf->size)
-                       break;
-       }
-
-       return 0;
-}
-
-bool git_buf_text_is_binary(const git_buf *buf)
-{
-       const char *scan = buf->ptr, *end = buf->ptr + buf->size;
-       git_bom_t bom;
-       int printable = 0, nonprintable = 0;
-
-       scan += git_buf_text_detect_bom(&bom, buf);
-
-       if (bom > GIT_BOM_UTF8)
-               return 1;
-
-       while (scan < end) {
-               unsigned char c = *scan++;
-
-               /* Printable characters are those above SPACE (0x1F) excluding DEL,
-                * and including BS, ESC and FF.
-                */
-               if ((c > 0x1F && c != 127) || c == '\b' || c == '\033' || c == '\014')
-                       printable++;
-               else if (c == '\0')
-                       return true;
-               else if (!git__isspace(c))
-                       nonprintable++;
-       }
-
-       return ((printable >> 7) < nonprintable);
-}
-
-bool git_buf_text_contains_nul(const git_buf *buf)
-{
-       return (memchr(buf->ptr, '\0', buf->size) != NULL);
-}
-
-int git_buf_text_detect_bom(git_bom_t *bom, const git_buf *buf)
-{
-       const char *ptr;
-       size_t len;
-
-       *bom = GIT_BOM_NONE;
-       /* need at least 2 bytes to look for any BOM */
-       if (buf->size < 2)
-               return 0;
-
-       ptr = buf->ptr;
-       len = buf->size;
-
-       switch (*ptr++) {
-       case 0:
-               if (len >= 4 && ptr[0] == 0 && ptr[1] == '\xFE' && ptr[2] == '\xFF') {
-                       *bom = GIT_BOM_UTF32_BE;
-                       return 4;
-               }
-               break;
-       case '\xEF':
-               if (len >= 3 && ptr[0] == '\xBB' && ptr[1] == '\xBF') {
-                       *bom = GIT_BOM_UTF8;
-                       return 3;
-               }
-               break;
-       case '\xFE':
-               if (*ptr == '\xFF') {
-                       *bom = GIT_BOM_UTF16_BE;
-                       return 2;
-               }
-               break;
-       case '\xFF':
-               if (*ptr != '\xFE')
-                       break;
-               if (len >= 4 && ptr[1] == 0 && ptr[2] == 0) {
-                       *bom = GIT_BOM_UTF32_LE;
-                       return 4;
-               } else {
-                       *bom = GIT_BOM_UTF16_LE;
-                       return 2;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-bool git_buf_text_gather_stats(
-       git_buf_text_stats *stats, const git_buf *buf, bool skip_bom)
-{
-       const char *scan = buf->ptr, *end = buf->ptr + buf->size;
-       int skip;
-
-       memset(stats, 0, sizeof(*stats));
-
-       /* BOM detection */
-       skip = git_buf_text_detect_bom(&stats->bom, buf);
-       if (skip_bom)
-               scan += skip;
-
-       /* Ignore EOF character */
-       if (buf->size > 0 && end[-1] == '\032')
-               end--;
-
-       /* Counting loop */
-       while (scan < end) {
-               unsigned char c = *scan++;
-
-               if (c > 0x1F && c != 0x7F)
-                       stats->printable++;
-               else switch (c) {
-                       case '\0':
-                               stats->nul++;
-                               stats->nonprintable++;
-                               break;
-                       case '\n':
-                               stats->lf++;
-                               break;
-                       case '\r':
-                               stats->cr++;
-                               if (scan < end && *scan == '\n')
-                                       stats->crlf++;
-                               break;
-                       case '\t': case '\f': case '\v': case '\b': case 0x1b: /*ESC*/
-                               stats->printable++;
-                               break;
-                       default:
-                               stats->nonprintable++;
-                               break;
-                       }
-       }
-
-       /* Treat files with a bare CR as binary */
-       return (stats->cr != stats->crlf || stats->nul > 0 ||
-               ((stats->printable >> 7) < stats->nonprintable));
-}
diff --git a/src/buf_text.h b/src/buf_text.h
deleted file mode 100644 (file)
index 726b0ae..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_buf_text_h__
-#define INCLUDE_buf_text_h__
-
-#include "common.h"
-
-#include "buffer.h"
-
-typedef enum {
-       GIT_BOM_NONE = 0,
-       GIT_BOM_UTF8 = 1,
-       GIT_BOM_UTF16_LE = 2,
-       GIT_BOM_UTF16_BE = 3,
-       GIT_BOM_UTF32_LE = 4,
-       GIT_BOM_UTF32_BE = 5
-} git_bom_t;
-
-typedef struct {
-       git_bom_t bom; /* BOM found at head of text */
-       unsigned int nul, cr, lf, crlf; /* NUL, CR, LF and CRLF counts */
-       unsigned int printable, nonprintable; /* These are just approximations! */
-} git_buf_text_stats;
-
-/**
- * Append string to buffer, prefixing each character from `esc_chars` with
- * `esc_with` string.
- *
- * @param buf Buffer to append data to
- * @param string String to escape and append
- * @param esc_chars Characters to be escaped
- * @param esc_with String to insert in from of each found character
- * @return 0 on success, <0 on failure (probably allocation problem)
- */
-extern int git_buf_text_puts_escaped(
-       git_buf *buf,
-       const char *string,
-       const char *esc_chars,
-       const char *esc_with);
-
-/**
- * Append string escaping characters that are regex special
- */
-GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string)
-{
-       return git_buf_text_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\");
-}
-
-/**
- * Unescape all characters in a buffer in place
- *
- * I.e. remove backslashes
- */
-extern void git_buf_text_unescape(git_buf *buf);
-
-/**
- * Replace all \r\n with \n.
- *
- * @return 0 on success, -1 on memory error
- */
-extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src);
-
-/**
- * Replace all \n with \r\n. Does not modify existing \r\n.
- *
- * @return 0 on success, -1 on memory error
- */
-extern int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src);
-
-/**
- * Fill buffer with the common prefix of a array of strings
- *
- * Buffer will be set to empty if there is no common prefix
- */
-extern int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strs);
-
-/**
- * Check quickly if buffer looks like it contains binary data
- *
- * @param buf Buffer to check
- * @return true if buffer looks like non-text data
- */
-extern bool git_buf_text_is_binary(const git_buf *buf);
-
-/**
- * Check quickly if buffer contains a NUL byte
- *
- * @param buf Buffer to check
- * @return true if buffer contains a NUL byte
- */
-extern bool git_buf_text_contains_nul(const git_buf *buf);
-
-/**
- * Check if a buffer begins with a UTF BOM
- *
- * @param bom Set to the type of BOM detected or GIT_BOM_NONE
- * @param buf Buffer in which to check the first bytes for a BOM
- * @return Number of bytes of BOM data (or 0 if no BOM found)
- */
-extern int git_buf_text_detect_bom(git_bom_t *bom, const git_buf *buf);
-
-/**
- * Gather stats for a piece of text
- *
- * Fill the `stats` structure with counts of unreadable characters, carriage
- * returns, etc, so it can be used in heuristics.  This automatically skips
- * a trailing EOF (\032 character).  Also it will look for a BOM at the
- * start of the text and can be told to skip that as well.
- *
- * @param stats Structure to be filled in
- * @param buf Text to process
- * @param skip_bom Exclude leading BOM from stats if true
- * @return Does the buffer heuristically look like binary data
- */
-extern bool git_buf_text_gather_stats(
-       git_buf_text_stats *stats, const git_buf *buf, bool skip_bom);
-
-#endif
index c203650c752c77c5b1c88a3d85aa0a3af9e9a3fb..fe087ea11166e222e0737508f15e0838bbf4b7be 100644 (file)
@@ -7,7 +7,6 @@
 #include "buffer.h"
 #include "posix.h"
 #include "git2/buffer.h"
-#include "buf_text.h"
 #include <ctype.h>
 
 /* Used as default value for git_buf->ptr so that people can always
@@ -140,13 +139,17 @@ void git_buf_free(git_buf *buf)
 }
 #endif
 
-void git_buf_sanitize(git_buf *buf)
+int git_buf_sanitize(git_buf *buf)
 {
        if (buf->ptr == NULL) {
-               assert(buf->size == 0 && buf->asize == 0);
+               GIT_ASSERT_ARG(buf->size == 0 && buf->asize == 0);
+
                buf->ptr = git_buf__initbuf;
-       } else if (buf->asize > buf->size)
+       } else if (buf->asize > buf->size) {
                buf->ptr[buf->size] = '\0';
+       }
+
+       return 0;
 }
 
 void git_buf_clear(git_buf *buf)
@@ -183,16 +186,6 @@ int git_buf_set(git_buf *buf, const void *data, size_t len)
        return 0;
 }
 
-int git_buf_is_binary(const git_buf *buf)
-{
-       return git_buf_text_is_binary(buf);
-}
-
-int git_buf_contains_nul(const git_buf *buf)
-{
-       return git_buf_text_contains_nul(buf);
-}
-
 int git_buf_sets(git_buf *buf, const char *string)
 {
        return git_buf_set(buf, string, string ? strlen(string) : 0);
@@ -225,7 +218,7 @@ int git_buf_put(git_buf *buf, const char *data, size_t len)
        if (len) {
                size_t new_size;
 
-               assert(data);
+               GIT_ASSERT_ARG(data);
 
                GIT_ERROR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
                GIT_ERROR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
@@ -239,7 +232,8 @@ int git_buf_put(git_buf *buf, const char *data, size_t len)
 
 int git_buf_puts(git_buf *buf, const char *string)
 {
-       assert(string);
+       GIT_ASSERT_ARG(string);
+
        return git_buf_put(buf, string, strlen(string));
 }
 
@@ -319,7 +313,7 @@ int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len)
                return -1;
        }
 
-       assert(len % 4 == 0);
+       GIT_ASSERT_ARG(len % 4 == 0);
        GIT_ERROR_CHECK_ALLOC_ADD(&new_size, (len / 4 * 3), buf->size);
        GIT_ERROR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
        ENSURE_SIZE(buf, new_size);
@@ -551,22 +545,26 @@ int git_buf_printf(git_buf *buf, const char *format, ...)
        return r;
 }
 
-void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf)
+int git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf)
 {
        size_t copylen;
 
-       assert(data && datasize && buf);
+       GIT_ASSERT_ARG(data);
+       GIT_ASSERT_ARG(datasize);
+       GIT_ASSERT_ARG(buf);
 
        data[0] = '\0';
 
        if (buf->size == 0 || buf->asize <= 0)
-               return;
+               return 0;
 
        copylen = buf->size;
        if (copylen > datasize - 1)
                copylen = datasize - 1;
        memmove(data, buf->ptr, copylen);
        data[copylen] = '\0';
+
+       return 0;
 }
 
 void git_buf_consume_bytes(git_buf *buf, size_t len)
@@ -602,6 +600,13 @@ void git_buf_shorten(git_buf *buf, size_t amount)
                git_buf_clear(buf);
 }
 
+void git_buf_truncate_at_char(git_buf *buf, char separator)
+{
+       ssize_t idx = git_buf_find(buf, separator);
+       if (idx >= 0)
+               git_buf_truncate(buf, (size_t)idx);
+}
+
 void git_buf_rtruncate_at_char(git_buf *buf, char separator)
 {
        ssize_t idx = git_buf_rfind_next(buf, separator);
@@ -672,7 +677,7 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
 
        va_start(ap, nbuf);
        for (i = 0; i < nbuf; ++i) {
-               const charsegment;
+               const char *segment;
                size_t segment_len;
 
                segment = va_arg(ap, const char *);
@@ -704,7 +709,7 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
 
        va_start(ap, nbuf);
        for (i = 0; i < nbuf; ++i) {
-               const charsegment;
+               const char *segment;
                size_t segment_len;
 
                segment = va_arg(ap, const char *);
@@ -760,7 +765,7 @@ int git_buf_join(
 
        /* not safe to have str_b point internally to the buffer */
        if (buf->size)
-               assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
+               GIT_ASSERT_ARG(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
 
        /* figure out if we need to insert a separator */
        if (separator && strlen_a) {
@@ -810,9 +815,9 @@ int git_buf_join3(
        char *tgt;
 
        /* for this function, disallow pointers into the existing buffer */
-       assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
-       assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
-       assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
+       GIT_ASSERT(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
+       GIT_ASSERT(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
+       GIT_ASSERT(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
 
        if (separator) {
                if (len_a > 0) {
@@ -885,7 +890,9 @@ int git_buf_splice(
        char *splice_loc;
        size_t new_size, alloc_size;
 
-       assert(buf && where <= buf->size && nb_to_remove <= buf->size - where);
+       GIT_ASSERT(buf);
+       GIT_ASSERT(where <= buf->size);
+       GIT_ASSERT(nb_to_remove <= buf->size - where);
 
        splice_loc = buf->ptr + where;
 
@@ -1047,3 +1054,313 @@ invalid:
        git_error_set(GIT_ERROR_INVALID, "invalid quoted line");
        return -1;
 }
+
+int git_buf_puts_escaped(
+       git_buf *buf,
+       const char *string,
+       const char *esc_chars,
+       const char *esc_with)
+{
+       const char *scan;
+       size_t total = 0, esc_len = strlen(esc_with), count, alloclen;
+
+       if (!string)
+               return 0;
+
+       for (scan = string; *scan; ) {
+               /* count run of non-escaped characters */
+               count = strcspn(scan, esc_chars);
+               total += count;
+               scan += count;
+               /* count run of escaped characters */
+               count = strspn(scan, esc_chars);
+               total += count * (esc_len + 1);
+               scan += count;
+       }
+
+       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, total, 1);
+       if (git_buf_grow_by(buf, alloclen) < 0)
+               return -1;
+
+       for (scan = string; *scan; ) {
+               count = strcspn(scan, esc_chars);
+
+               memmove(buf->ptr + buf->size, scan, count);
+               scan += count;
+               buf->size += count;
+
+               for (count = strspn(scan, esc_chars); count > 0; --count) {
+                       /* copy escape sequence */
+                       memmove(buf->ptr + buf->size, esc_with, esc_len);
+                       buf->size += esc_len;
+                       /* copy character to be escaped */
+                       buf->ptr[buf->size] = *scan;
+                       buf->size++;
+                       scan++;
+               }
+       }
+
+       buf->ptr[buf->size] = '\0';
+
+       return 0;
+}
+
+void git_buf_unescape(git_buf *buf)
+{
+       buf->size = git__unescape(buf->ptr);
+}
+
+int git_buf_crlf_to_lf(git_buf *tgt, const git_buf *src)
+{
+       const char *scan = src->ptr;
+       const char *scan_end = src->ptr + src->size;
+       const char *next = memchr(scan, '\r', src->size);
+       size_t new_size;
+       char *out;
+
+       GIT_ASSERT(tgt != src);
+
+       if (!next)
+               return git_buf_set(tgt, src->ptr, src->size);
+
+       /* reduce reallocs while in the loop */
+       GIT_ERROR_CHECK_ALLOC_ADD(&new_size, src->size, 1);
+       if (git_buf_grow(tgt, new_size) < 0)
+               return -1;
+
+       out = tgt->ptr;
+       tgt->size = 0;
+
+       /* Find the next \r and copy whole chunk up to there to tgt */
+       for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) {
+               if (next > scan) {
+                       size_t copylen = (size_t)(next - scan);
+                       memcpy(out, scan, copylen);
+                       out += copylen;
+               }
+
+               /* Do not drop \r unless it is followed by \n */
+               if (next + 1 == scan_end || next[1] != '\n')
+                       *out++ = '\r';
+       }
+
+       /* Copy remaining input into dest */
+       if (scan < scan_end) {
+               size_t remaining = (size_t)(scan_end - scan);
+               memcpy(out, scan, remaining);
+               out += remaining;
+       }
+
+       tgt->size = (size_t)(out - tgt->ptr);
+       tgt->ptr[tgt->size] = '\0';
+
+       return 0;
+}
+
+int git_buf_lf_to_crlf(git_buf *tgt, const git_buf *src)
+{
+       const char *start = src->ptr;
+       const char *end = start + src->size;
+       const char *scan = start;
+       const char *next = memchr(scan, '\n', src->size);
+       size_t alloclen;
+
+       GIT_ASSERT(tgt != src);
+
+       if (!next)
+               return git_buf_set(tgt, src->ptr, src->size);
+
+       /* attempt to reduce reallocs while in the loop */
+       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, src->size, src->size >> 4);
+       GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
+       if (git_buf_grow(tgt, alloclen) < 0)
+               return -1;
+       tgt->size = 0;
+
+       for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
+               size_t copylen = next - scan;
+
+               /* if we find mixed line endings, carry on */
+               if (copylen && next[-1] == '\r')
+                       copylen--;
+
+               GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, copylen, 3);
+               if (git_buf_grow_by(tgt, alloclen) < 0)
+                       return -1;
+
+               if (copylen) {
+                       memcpy(tgt->ptr + tgt->size, scan, copylen);
+                       tgt->size += copylen;
+               }
+
+               tgt->ptr[tgt->size++] = '\r';
+               tgt->ptr[tgt->size++] = '\n';
+       }
+
+       tgt->ptr[tgt->size] = '\0';
+       return git_buf_put(tgt, scan, end - scan);
+}
+
+int git_buf_common_prefix(git_buf *buf, char *const *const strings, size_t count)
+{
+       size_t i;
+       const char *str, *pfx;
+
+       git_buf_clear(buf);
+
+       if (!strings || !count)
+               return 0;
+
+       /* initialize common prefix to first string */
+       if (git_buf_sets(buf, strings[0]) < 0)
+               return -1;
+
+       /* go through the rest of the strings, truncating to shared prefix */
+       for (i = 1; i < count; ++i) {
+
+               for (str = strings[i], pfx = buf->ptr;
+                    *str && *str == *pfx;
+                    str++, pfx++)
+                       /* scanning */;
+
+               git_buf_truncate(buf, pfx - buf->ptr);
+
+               if (!buf->size)
+                       break;
+       }
+
+       return 0;
+}
+
+int git_buf_is_binary(const git_buf *buf)
+{
+       const char *scan = buf->ptr, *end = buf->ptr + buf->size;
+       git_buf_bom_t bom;
+       int printable = 0, nonprintable = 0;
+
+       scan += git_buf_detect_bom(&bom, buf);
+
+       if (bom > GIT_BUF_BOM_UTF8)
+               return 1;
+
+       while (scan < end) {
+               unsigned char c = *scan++;
+
+               /* Printable characters are those above SPACE (0x1F) excluding DEL,
+                * and including BS, ESC and FF.
+                */
+               if ((c > 0x1F && c != 127) || c == '\b' || c == '\033' || c == '\014')
+                       printable++;
+               else if (c == '\0')
+                       return true;
+               else if (!git__isspace(c))
+                       nonprintable++;
+       }
+
+       return ((printable >> 7) < nonprintable);
+}
+
+int git_buf_contains_nul(const git_buf *buf)
+{
+       return (memchr(buf->ptr, '\0', buf->size) != NULL);
+}
+
+int git_buf_detect_bom(git_buf_bom_t *bom, const git_buf *buf)
+{
+       const char *ptr;
+       size_t len;
+
+       *bom = GIT_BUF_BOM_NONE;
+       /* need at least 2 bytes to look for any BOM */
+       if (buf->size < 2)
+               return 0;
+
+       ptr = buf->ptr;
+       len = buf->size;
+
+       switch (*ptr++) {
+       case 0:
+               if (len >= 4 && ptr[0] == 0 && ptr[1] == '\xFE' && ptr[2] == '\xFF') {
+                       *bom = GIT_BUF_BOM_UTF32_BE;
+                       return 4;
+               }
+               break;
+       case '\xEF':
+               if (len >= 3 && ptr[0] == '\xBB' && ptr[1] == '\xBF') {
+                       *bom = GIT_BUF_BOM_UTF8;
+                       return 3;
+               }
+               break;
+       case '\xFE':
+               if (*ptr == '\xFF') {
+                       *bom = GIT_BUF_BOM_UTF16_BE;
+                       return 2;
+               }
+               break;
+       case '\xFF':
+               if (*ptr != '\xFE')
+                       break;
+               if (len >= 4 && ptr[1] == 0 && ptr[2] == 0) {
+                       *bom = GIT_BUF_BOM_UTF32_LE;
+                       return 4;
+               } else {
+                       *bom = GIT_BUF_BOM_UTF16_LE;
+                       return 2;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+bool git_buf_gather_text_stats(
+       git_buf_text_stats *stats, const git_buf *buf, bool skip_bom)
+{
+       const char *scan = buf->ptr, *end = buf->ptr + buf->size;
+       int skip;
+
+       memset(stats, 0, sizeof(*stats));
+
+       /* BOM detection */
+       skip = git_buf_detect_bom(&stats->bom, buf);
+       if (skip_bom)
+               scan += skip;
+
+       /* Ignore EOF character */
+       if (buf->size > 0 && end[-1] == '\032')
+               end--;
+
+       /* Counting loop */
+       while (scan < end) {
+               unsigned char c = *scan++;
+
+               if (c > 0x1F && c != 0x7F)
+                       stats->printable++;
+               else switch (c) {
+                       case '\0':
+                               stats->nul++;
+                               stats->nonprintable++;
+                               break;
+                       case '\n':
+                               stats->lf++;
+                               break;
+                       case '\r':
+                               stats->cr++;
+                               if (scan < end && *scan == '\n')
+                                       stats->crlf++;
+                               break;
+                       case '\t': case '\f': case '\v': case '\b': case 0x1b: /*ESC*/
+                               stats->printable++;
+                               break;
+                       default:
+                               stats->nonprintable++;
+                               break;
+                       }
+       }
+
+       /* Treat files with a bare CR as binary */
+       return (stats->cr != stats->crlf || stats->nul > 0 ||
+               ((stats->printable >> 7) < stats->nonprintable));
+}
index 6b717d2e90cc32b11d4a80190b866353fd155821..75930e2094461aed414530aa6151859086e06e97 100644 (file)
  * } git_buf;
  */
 
+typedef enum {
+       GIT_BUF_BOM_NONE = 0,
+       GIT_BUF_BOM_UTF8 = 1,
+       GIT_BUF_BOM_UTF16_LE = 2,
+       GIT_BUF_BOM_UTF16_BE = 3,
+       GIT_BUF_BOM_UTF32_LE = 4,
+       GIT_BUF_BOM_UTF32_BE = 5
+} git_buf_bom_t;
+
+typedef struct {
+       git_buf_bom_t bom; /* BOM found at head of text */
+       unsigned int nul, cr, lf, crlf; /* NUL, CR, LF and CRLF counts */
+       unsigned int printable, nonprintable; /* These are just approximations! */
+} git_buf_text_stats;
+
 extern char git_buf__initbuf[];
 extern char git_buf__oom[];
 
 /* Use to initialize buffer structure when git_buf is on stack */
 #define GIT_BUF_INIT { git_buf__initbuf, 0, 0 }
 
+/**
+ * Static initializer for git_buf from static buffer
+ */
+#ifdef GIT_DEPRECATE_HARD
+# define GIT_BUF_INIT_CONST(STR,LEN) { (char *)(STR), 0, (size_t)(LEN) }
+#endif
+
 GIT_INLINE(bool) git_buf_is_allocated(const git_buf *buf)
 {
        return (buf->ptr != NULL && buf->asize > 0);
@@ -36,6 +58,33 @@ GIT_INLINE(bool) git_buf_is_allocated(const git_buf *buf)
  */
 extern int git_buf_init(git_buf *buf, size_t initial_size);
 
+#ifdef GIT_DEPRECATE_HARD
+
+/**
+ * Resize the buffer allocation to make more space.
+ *
+ * This will attempt to grow the buffer to accommodate the target size.
+ *
+ * If the buffer refers to memory that was not allocated by libgit2 (i.e.
+ * the `asize` field is zero), then `ptr` will be replaced with a newly
+ * allocated block of data.  Be careful so that memory allocated by the
+ * caller is not lost.  As a special variant, if you pass `target_size` as
+ * 0 and the memory is not allocated by libgit2, this will allocate a new
+ * buffer of size `size` and copy the external data into it.
+ *
+ * Currently, this will never shrink a buffer, only expand it.
+ *
+ * If the allocation fails, this will return an error and the buffer will be
+ * marked as invalid for future operations, invaliding the contents.
+ *
+ * @param buffer The buffer to be resized; may or may not be allocated yet
+ * @param target_size The desired available size
+ * @return 0 on success, -1 on allocation failure
+ */
+int git_buf_grow(git_buf *buffer, size_t target_size);
+
+#endif
+
 /**
  * Resize the buffer allocation to make more space.
  *
@@ -69,7 +118,7 @@ extern int git_buf_try_grow(
  * git_buf__initbuf. If a buffer with a non-NULL ptr is passed in, this method
  * assures that the buffer is '\0'-terminated.
  */
-extern void git_buf_sanitize(git_buf *buf);
+extern int git_buf_sanitize(git_buf *buf);
 
 extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
 extern char *git_buf_detach(git_buf *buf);
@@ -105,6 +154,11 @@ GIT_INLINE(bool) git_buf_oom(const git_buf *buf)
  * return code of these functions and call them in a series then just call
  * git_buf_oom at the end.
  */
+
+#ifdef GIT_DEPRECATE_HARD
+int git_buf_set(git_buf *buffer, const void *data, size_t datalen);
+#endif
+
 int git_buf_sets(git_buf *buf, const char *string);
 int git_buf_putc(git_buf *buf, char c);
 int git_buf_putcn(git_buf *buf, char c, size_t len);
@@ -117,6 +171,7 @@ void git_buf_consume_bytes(git_buf *buf, size_t len);
 void git_buf_consume(git_buf *buf, const char *end);
 void git_buf_truncate(git_buf *buf, size_t len);
 void git_buf_shorten(git_buf *buf, size_t amount);
+void git_buf_truncate_at_char(git_buf *buf, char separator);
 void git_buf_rtruncate_at_char(git_buf *path, char separator);
 
 /** General join with separator */
@@ -145,7 +200,7 @@ GIT_INLINE(size_t) git_buf_len(const git_buf *buf)
        return buf->size;
 }
 
-void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf);
+int git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf);
 
 #define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1)
 
@@ -219,4 +274,101 @@ int git_buf_splice(
        const char *data,
        size_t nb_to_insert);
 
+/**
+ * Append string to buffer, prefixing each character from `esc_chars` with
+ * `esc_with` string.
+ *
+ * @param buf Buffer to append data to
+ * @param string String to escape and append
+ * @param esc_chars Characters to be escaped
+ * @param esc_with String to insert in from of each found character
+ * @return 0 on success, <0 on failure (probably allocation problem)
+ */
+extern int git_buf_puts_escaped(
+       git_buf *buf,
+       const char *string,
+       const char *esc_chars,
+       const char *esc_with);
+
+/**
+ * Append string escaping characters that are regex special
+ */
+GIT_INLINE(int) git_buf_puts_escape_regex(git_buf *buf, const char *string)
+{
+       return git_buf_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\");
+}
+
+/**
+ * Unescape all characters in a buffer in place
+ *
+ * I.e. remove backslashes
+ */
+extern void git_buf_unescape(git_buf *buf);
+
+/**
+ * Replace all \r\n with \n.
+ *
+ * @return 0 on success, -1 on memory error
+ */
+extern int git_buf_crlf_to_lf(git_buf *tgt, const git_buf *src);
+
+/**
+ * Replace all \n with \r\n. Does not modify existing \r\n.
+ *
+ * @return 0 on success, -1 on memory error
+ */
+extern int git_buf_lf_to_crlf(git_buf *tgt, const git_buf *src);
+
+/**
+ * Fill buffer with the common prefix of a array of strings
+ *
+ * Buffer will be set to empty if there is no common prefix
+ */
+extern int git_buf_common_prefix(git_buf *buf, char *const *const strings, size_t count);
+
+/**
+ * Check if a buffer begins with a UTF BOM
+ *
+ * @param bom Set to the type of BOM detected or GIT_BOM_NONE
+ * @param buf Buffer in which to check the first bytes for a BOM
+ * @return Number of bytes of BOM data (or 0 if no BOM found)
+ */
+extern int git_buf_detect_bom(git_buf_bom_t *bom, const git_buf *buf);
+
+/**
+ * Gather stats for a piece of text
+ *
+ * Fill the `stats` structure with counts of unreadable characters, carriage
+ * returns, etc, so it can be used in heuristics.  This automatically skips
+ * a trailing EOF (\032 character).  Also it will look for a BOM at the
+ * start of the text and can be told to skip that as well.
+ *
+ * @param stats Structure to be filled in
+ * @param buf Text to process
+ * @param skip_bom Exclude leading BOM from stats if true
+ * @return Does the buffer heuristically look like binary data
+ */
+extern bool git_buf_gather_text_stats(
+       git_buf_text_stats *stats, const git_buf *buf, bool skip_bom);
+
+#ifdef GIT_DEPRECATE_HARD
+
+/**
+* Check quickly if buffer looks like it contains binary data
+*
+* @param buf Buffer to check
+* @return 1 if buffer looks like non-text data
+*/
+int git_buf_is_binary(const git_buf *buf);
+
+/**
+* Check quickly if buffer contains a NUL byte
+*
+* @param buf Buffer to check
+* @return 1 if buffer contains a NUL byte
+*/
+int git_buf_contains_nul(const git_buf *buf);
+
+#endif
+
 #endif
index a76da50d7a1d18548481939d7f9519125ace1d02..2f68e357cbd81a4c3392cbcd477c54ebf14a2789 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "repository.h"
 #include "commit.h"
-#include "thread-utils.h"
+#include "thread.h"
 #include "util.h"
 #include "odb.h"
 #include "object.h"
@@ -235,7 +235,7 @@ void git_cached_obj_decref(void *_obj)
 {
        git_cached_obj *obj = _obj;
 
-       if (git_atomic_dec(&obj->refcount) == 0) {
+       if (git_atomic32_dec(&obj->refcount) == 0) {
                switch (obj->flags) {
                case GIT_CACHE_STORE_RAW:
                        git_odb_object__free(_obj);
index 1e617923664f5d6630257ec2d66c3352628a30c6..42c4fa80d7f6d2b919b8650cd8d538c4191cdfae 100644 (file)
@@ -13,7 +13,7 @@
 #include "git2/oid.h"
 #include "git2/odb.h"
 
-#include "thread-utils.h"
+#include "thread.h"
 #include "oidmap.h"
 
 enum {
@@ -23,11 +23,11 @@ enum {
 };
 
 typedef struct {
-       git_oid    oid;
-       int16_t    type;  /* git_object_t value */
-       uint16_t   flags; /* GIT_CACHE_STORE value */
-       size_t     size;
-       git_atomic refcount;
+       git_oid      oid;
+       int16_t      type;  /* git_object_t value */
+       uint16_t     flags; /* GIT_CACHE_STORE value */
+       size_t       size;
+       git_atomic32 refcount;
 } git_cached_obj;
 
 typedef struct {
@@ -61,7 +61,7 @@ GIT_INLINE(size_t) git_cache_size(git_cache *cache)
 GIT_INLINE(void) git_cached_obj_incref(void *_obj)
 {
        git_cached_obj *obj = _obj;
-       git_atomic_inc(&obj->refcount);
+       git_atomic32_inc(&obj->refcount);
 }
 
 void git_cached_obj_decref(void *_obj);
index 7ade561f3def5b31dd253e6bfd7054aa4b05fbdd..f701b2d9351912e6259e9ae8a4107915f597a896 100644 (file)
 #      endif
 #endif
 
-#ifdef __GNUC__
-#      define GIT_TYPEOF(x) (__typeof__(x))
-#else
-#      define GIT_TYPEOF(x)
-#endif
-
 #if defined(__GNUC__)
 #      define GIT_ALIGN(x,size) x __attribute__ ((aligned(size)))
 #elif defined(_MSC_VER)
 #      define GIT_ALIGN(x,size) x
 #endif
 
-#define GIT_UNUSED(x) ((void)(x))
+#if defined(__GNUC__)
+# define GIT_UNUSED(x)                                                         \
+       do {                                                                   \
+               __typeof__(x) _unused __attribute__((unused));                 \
+               _unused = (x);                                                 \
+       } while (0)
+#else
+# define GIT_UNUSED(x) ((void)(x))
+#endif
 
-/* Define the printf format specifer to use for size_t output */
+/* Define the printf format specifier to use for size_t output */
 #if defined(_MSC_VER) || defined(__MINGW32__)
 
 /* Visual Studio 2012 and prior lack PRId64 entirely */
index 94a2cb9fac045d420f16462017a9b4620ebbed5e..3a171066b4e725dba8783879301930ceb72e13e5 100644 (file)
@@ -26,7 +26,6 @@
 #include "diff.h"
 #include "diff_generate.h"
 #include "pathspec.h"
-#include "buf_text.h"
 #include "diff_xdiff.h"
 #include "path.h"
 #include "attr.h"
@@ -329,6 +328,9 @@ static int checkout_target_fullpath(
        if (path && git_buf_puts(&data->target_path, path) < 0)
                return -1;
 
+       if (git_path_validate_workdir_buf(data->repo, &data->target_path) < 0)
+               return -1;
+
        *out = &data->target_path;
 
        return 0;
@@ -1243,7 +1245,7 @@ static int checkout_conflict_append_remove(
        checkout_data *data = payload;
        const char *name;
 
-       assert(ancestor || ours || theirs);
+       GIT_ASSERT_ARG(ancestor || ours || theirs);
 
        if (ancestor)
                name = git__strdup(ancestor->path);
@@ -1278,14 +1280,14 @@ static int checkout_verify_paths(
        unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
 
        if (action & CHECKOUT_ACTION__REMOVE) {
-               if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
+               if (!git_path_validate(repo, delta->old_file.path, delta->old_file.mode, flags)) {
                        git_error_set(GIT_ERROR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
                        return -1;
                }
        }
 
        if (action & ~CHECKOUT_ACTION__REMOVE) {
-               if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) {
+               if (!git_path_validate(repo, delta->new_file.path, delta->new_file.mode, flags)) {
                        git_error_set(GIT_ERROR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
                        return -1;
                }
@@ -1487,7 +1489,9 @@ static int checkout_stream_write(
 static int checkout_stream_close(git_writestream *s)
 {
        struct checkout_stream *stream = (struct checkout_stream *)s;
-       assert(stream && stream->open);
+
+       GIT_ASSERT_ARG(stream);
+       GIT_ASSERT_ARG(stream->open);
 
        stream->open = 0;
        return p_close(stream->fd);
@@ -1509,15 +1513,14 @@ static int blob_content_to_file(
        int flags = data->opts.file_open_flags;
        mode_t file_mode = data->opts.file_mode ?
                data->opts.file_mode : entry_filemode;
-       git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
+       git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
        struct checkout_stream writer;
        mode_t mode;
        git_filter_list *fl = NULL;
        int fd;
        int error = 0;
 
-       if (hint_path == NULL)
-               hint_path = path;
+       GIT_ASSERT(hint_path != NULL);
 
        if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
                return error;
@@ -1532,13 +1535,13 @@ static int blob_content_to_file(
                return fd;
        }
 
-       filter_opts.attr_session = &data->attr_session;
-       filter_opts.temp_buf = &data->tmp;
+       filter_session.attr_session = &data->attr_session;
+       filter_session.temp_buf = &data->tmp;
 
        if (!data->opts.disable_filters &&
-               (error = git_filter_list__load_ext(
+               (error = git_filter_list__load(
                        &fl, data->repo, blob, hint_path,
-                       GIT_FILTER_TO_WORKTREE, &filter_opts))) {
+                       GIT_FILTER_TO_WORKTREE, &filter_session))) {
                p_close(fd);
                return error;
        }
@@ -1554,7 +1557,7 @@ static int blob_content_to_file(
 
        error = git_filter_list_stream_blob(fl, blob, &writer.base);
 
-       assert(writer.open == 0);
+       GIT_ASSERT(writer.open == 0);
 
        git_filter_list_free(fl);
 
@@ -1785,7 +1788,7 @@ static int checkout_blob(
        }
 
        error = checkout_write_content(
-               data, &file->id, fullpath->ptr, NULL, file->mode, &st);
+               data, &file->id, fullpath->ptr, file->path, file->mode, &st);
 
        /* update the index unless prevented */
        if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
@@ -1971,12 +1974,12 @@ static int checkout_write_entry(
        checkout_conflictdata *conflict,
        const git_index_entry *side)
 {
-       const char *hint_path = NULL, *suffix;
+       const char *hint_path, *suffix;
        git_buf *fullpath;
        struct stat st;
        int error;
 
-       assert (side == conflict->ours || side == conflict->theirs);
+       GIT_ASSERT(side == conflict->ours || side == conflict->theirs);
 
        if (checkout_target_fullpath(&fullpath, data, side->path) < 0)
                return -1;
@@ -1994,10 +1997,10 @@ static int checkout_write_entry(
 
                if (checkout_path_suffixed(fullpath, suffix) < 0)
                        return -1;
-
-               hint_path = side->path;
        }
 
+       hint_path = side->path;
+
        if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
                (error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0)
                return error;
@@ -2030,7 +2033,8 @@ static int checkout_merge_path(
        const char *our_label_raw, *their_label_raw, *suffix;
        int error = 0;
 
-       if ((error = git_buf_joinpath(out, git_repository_workdir(data->repo), result->path)) < 0)
+       if ((error = git_buf_joinpath(out, data->opts.target_directory, result->path)) < 0 ||
+           (error = git_path_validate_workdir_buf(data->repo, out)) < 0)
                return error;
 
        /* Most conflicts simply use the filename in the index */
@@ -2059,7 +2063,7 @@ static int checkout_write_merge(
        git_merge_file_result result = {0};
        git_filebuf output = GIT_FILEBUF_INIT;
        git_filter_list *fl = NULL;
-       git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
+       git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
        int error = 0;
 
        if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
@@ -2109,13 +2113,13 @@ static int checkout_write_merge(
                in_data.ptr = (char *)result.ptr;
                in_data.size = result.len;
 
-               filter_opts.attr_session = &data->attr_session;
-               filter_opts.temp_buf = &data->tmp;
+               filter_session.attr_session = &data->attr_session;
+               filter_session.temp_buf = &data->tmp;
 
-               if ((error = git_filter_list__load_ext(
-                               &fl, data->repo, NULL, git_buf_cstr(&path_workdir),
-                               GIT_FILTER_TO_WORKTREE, &filter_opts)) < 0 ||
-                       (error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
+               if ((error = git_filter_list__load(
+                               &fl, data->repo, NULL, result.path,
+                               GIT_FILTER_TO_WORKTREE, &filter_session)) < 0 ||
+                       (error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0)
                        goto done;
        } else {
                out_data.ptr = (char *)result.ptr;
@@ -2329,6 +2333,22 @@ static void checkout_data_clear(checkout_data *data)
        git_attr_session__free(&data->attr_session);
 }
 
+static int validate_target_directory(checkout_data *data)
+{
+       int error;
+
+       if ((error = git_path_validate_workdir(data->repo, data->opts.target_directory)) < 0)
+               return error;
+
+       if (git_path_isdir(data->opts.target_directory))
+               return 0;
+
+       error = checkout_mkdir(data, data->opts.target_directory, NULL,
+                              GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR);
+
+       return error;
+}
+
 static int checkout_data_init(
        checkout_data *data,
        git_iterator *target,
@@ -2361,10 +2381,7 @@ static int checkout_data_init(
 
        if (!data->opts.target_directory)
                data->opts.target_directory = git_repository_workdir(repo);
-       else if (!git_path_isdir(data->opts.target_directory) &&
-                        (error = checkout_mkdir(data,
-                               data->opts.target_directory, NULL,
-                               GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
+       else if ((error = validate_target_directory(data)) < 0)
                goto cleanup;
 
        if ((error = git_repository_index(&data->index, data->repo)) < 0)
@@ -2588,7 +2605,7 @@ int git_checkout_iterator(
        }
 
        /* Should not have case insensitivity mismatch */
-       assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
+       GIT_ASSERT(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
 
        /* Generate baseline-to-target diff which will include an entry for
         * every possible update that might need to be made.
@@ -2604,6 +2621,9 @@ int git_checkout_iterator(
        if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0)
                goto cleanup;
 
+       if (data.strategy & GIT_CHECKOUT_DRY_RUN)
+               goto cleanup;
+       
        data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
                counts[CHECKOUT_ACTION__REMOVE_CONFLICT] +
                counts[CHECKOUT_ACTION__UPDATE_BLOB] +
@@ -2639,7 +2659,7 @@ int git_checkout_iterator(
                (error = checkout_extensions_update_index(&data)) < 0)
                goto cleanup;
 
-       assert(data.completed_steps == data.total_steps);
+       GIT_ASSERT(data.completed_steps == data.total_steps);
 
        if (data.opts.perfdata_cb)
                data.opts.perfdata_cb(&data.perfdata, data.opts.perfdata_payload);
@@ -2767,7 +2787,8 @@ int git_checkout_head(
        git_repository *repo,
        const git_checkout_options *opts)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
+
        return git_checkout_tree(repo, NULL, opts);
 }
 
index 103897aaeb4b56f177132c7b6b5a634d7257e2ee..4287956c9c3a58e8816910019c224bfde5b20692 100644 (file)
@@ -126,7 +126,10 @@ int git_cherrypick_commit(
        git_tree *parent_tree = NULL, *our_tree = NULL, *cherrypick_tree = NULL;
        int parent = 0, error = 0;
 
-       assert(out && repo && cherrypick_commit && our_commit);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(cherrypick_commit);
+       GIT_ASSERT_ARG(our_commit);
 
        if (git_commit_parentcount(cherrypick_commit) > 1) {
                if (!mainline)
@@ -177,7 +180,8 @@ int git_cherrypick(
        git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
        int error = 0;
 
-       assert(repo && commit);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(commit);
 
        GIT_ERROR_CHECK_VERSION(given_opts, GIT_CHERRYPICK_OPTIONS_VERSION, "git_cherrypick_options");
 
index a93ec475f42a278e0aab33013fe18e114480672e..752df3b92d864f7772b2106a5aa4dd5d23ccc941 100644 (file)
@@ -231,7 +231,7 @@ static int update_head_to_remote(
 
        /* We know we have HEAD, let's see where it points */
        remote_head = refs[0];
-       assert(remote_head);
+       GIT_ASSERT(remote_head);
 
        remote_head_id = &remote_head->oid;
 
@@ -259,29 +259,41 @@ cleanup:
 
 static int update_head_to_branch(
                git_repository *repo,
-               const char *remote_name,
+               git_remote *remote,
                const char *branch,
                const char *reflog_message)
 {
        int retcode;
        git_buf remote_branch_name = GIT_BUF_INIT;
-       git_reference* remote_ref = NULL;
+       git_reference *remote_ref = NULL;
+       git_buf default_branch = GIT_BUF_INIT;
 
-       assert(remote_name && branch);
+       GIT_ASSERT_ARG(remote);
+       GIT_ASSERT_ARG(branch);
 
        if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
-               remote_name, branch)) < 0 )
+               git_remote_name(remote), branch)) < 0 )
                goto cleanup;
 
        if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
                goto cleanup;
 
-       retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch,
-                       reflog_message);
+       if ((retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch,
+                       reflog_message)) < 0)
+               goto cleanup;
+
+       if ((retcode = git_remote_default_branch(&default_branch, remote)) < 0)
+               goto cleanup;
+
+       if (!git_remote__matching_refspec(remote, git_buf_cstr(&default_branch)))
+               goto cleanup;
+
+       retcode = update_remote_head(repo, remote, &default_branch, reflog_message);
 
 cleanup:
        git_reference_free(remote_ref);
        git_buf_dispose(&remote_branch_name);
+       git_buf_dispose(&default_branch);
        return retcode;
 }
 
@@ -366,8 +378,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
        int error;
 
        if (branch)
-               error = update_head_to_branch(repo, git_remote_name(remote), branch,
-                               reflog_message);
+               error = update_head_to_branch(repo, remote, branch, reflog_message);
        /* Point HEAD to the same ref as the remote's head */
        else
                error = update_head_to_remote(repo, remote, reflog_message);
@@ -385,7 +396,8 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
        git_fetch_options fetch_opts;
        git_remote *remote;
 
-       assert(repo && _remote);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(_remote);
 
        if (!git_repository_is_empty(repo)) {
                git_error_set(GIT_ERROR_INVALID, "the repository is not empty");
@@ -452,7 +464,9 @@ static int git__clone(
        uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES;
        git_repository_create_cb repository_cb;
 
-       assert(out && url && local_path);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(url);
+       GIT_ASSERT_ARG(local_path);
 
        if (_options)
                memcpy(&options, _options, sizeof(git_clone_options));
@@ -575,7 +589,8 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_
        git_buf src_odb = GIT_BUF_INIT, dst_odb = GIT_BUF_INIT, src_path = GIT_BUF_INIT;
        git_buf reflog_message = GIT_BUF_INIT;
 
-       assert(repo && remote);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(remote);
 
        if (!git_repository_is_empty(repo)) {
                git_error_set(GIT_ERROR_INVALID, "the repository is not empty");
index cf9902d022b08130261b04b22f3fbd4ca8029522..96259d5bb14c9929f990efc49802eedd60aa265f 100644 (file)
@@ -53,7 +53,8 @@ static int git_commit__create_buffer_internal(
        size_t i = 0;
        const git_oid *parent;
 
-       assert(out && tree);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(tree);
 
        git_oid__writebuf(out, "tree ", tree);
 
@@ -229,7 +230,8 @@ int git_commit_create_v(
        int error = 0;
        commit_parent_varargs data;
 
-       assert(tree && git_tree_owner(tree) == repo);
+       GIT_ASSERT_ARG(tree);
+       GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
 
        data.total = parent_count;
        va_start(data.args, parent_count);
@@ -306,7 +308,8 @@ int git_commit_create(
 {
        commit_parent_data data = { parent_count, parents, repo };
 
-       assert(tree && git_tree_owner(tree) == repo);
+       GIT_ASSERT_ARG(tree);
+       GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
 
        return git_commit__create_internal(
                id, repo, update_ref, author, committer,
@@ -337,7 +340,8 @@ int git_commit_amend(
        git_reference *ref;
        int error;
 
-       assert(id && commit_to_amend);
+       GIT_ASSERT_ARG(id);
+       GIT_ASSERT_ARG(commit_to_amend);
 
        repo = git_commit_owner(commit_to_amend);
 
@@ -356,7 +360,7 @@ int git_commit_amend(
                git_oid_cpy(&tree_id, git_tree_id(old_tree));
                git_tree_free(old_tree);
        } else {
-               assert(git_tree_owner(tree) == repo);
+               GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
                git_oid_cpy(&tree_id, git_tree_id(tree));
        }
 
@@ -392,7 +396,8 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
        size_t header_len;
        git_signature dummy_sig;
 
-       assert(commit && data);
+       GIT_ASSERT_ARG(commit);
+       GIT_ASSERT_ARG(data);
 
        buffer = buffer_start;
 
@@ -506,28 +511,28 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
        return git_commit__parse_ext(_commit, odb_obj, 0);
 }
 
-#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
+#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \
        _rvalue git_commit_##_name(const git_commit *commit) \
        {\
-               assert(commit); \
+               GIT_ASSERT_ARG_WITH_RETVAL(commit, _invalid); \
                return _return; \
        }
 
-GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
-GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
-GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message)
-GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
-GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header)
-GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
-GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
-GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids))
-GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id)
+GIT_COMMIT_GETTER(const git_signature *, author, commit->author, NULL)
+GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer, NULL)
+GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message, NULL)
+GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding, NULL)
+GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header, NULL)
+GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time, INT64_MIN)
+GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset, -1)
+GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids), 0)
+GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id, NULL)
 
 const char *git_commit_message(const git_commit *commit)
 {
        const char *message;
 
-       assert(commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
 
        message = commit->raw_message;
 
@@ -544,7 +549,7 @@ const char *git_commit_summary(git_commit *commit)
        const char *msg, *space;
        bool space_contains_newline = false;
 
-       assert(commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
 
        if (!commit->summary) {
                for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) {
@@ -587,7 +592,7 @@ const char *git_commit_body(git_commit *commit)
 {
        const char *msg, *end;
 
-       assert(commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
 
        if (!commit->body) {
                /* search for end of summary */
@@ -612,14 +617,14 @@ const char *git_commit_body(git_commit *commit)
 
 int git_commit_tree(git_tree **tree_out, const git_commit *commit)
 {
-       assert(commit);
+       GIT_ASSERT_ARG(commit);
        return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id);
 }
 
 const git_oid *git_commit_parent_id(
        const git_commit *commit, unsigned int n)
 {
-       assert(commit);
+       GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
 
        return git_array_get(commit->parent_ids, n);
 }
@@ -628,7 +633,7 @@ int git_commit_parent(
        git_commit **parent, const git_commit *commit, unsigned int n)
 {
        const git_oid *parent_id;
-       assert(commit);
+       GIT_ASSERT_ARG(commit);
 
        parent_id = git_commit_parent_id(commit, n);
        if (parent_id == NULL) {
@@ -647,7 +652,8 @@ int git_commit_nth_gen_ancestor(
        git_commit *current, *parent = NULL;
        int error;
 
-       assert(ancestor && commit);
+       GIT_ASSERT_ARG(ancestor);
+       GIT_ASSERT_ARG(commit);
 
        if (git_commit_dup(&current, (git_commit *)commit) < 0)
                return -1;
@@ -840,7 +846,8 @@ int git_commit_create_buffer(git_buf *out,
        git_array_oid_t parents_arr = GIT_ARRAY_INIT;
        const git_oid *tree_id;
 
-       assert(tree && git_tree_owner(tree) == repo);
+       GIT_ASSERT_ARG(tree);
+       GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
 
        tree_id = git_tree_id(tree);
 
@@ -859,11 +866,13 @@ int git_commit_create_buffer(git_buf *out,
 /**
  * Append to 'out' properly marking continuations when there's a newline in 'content'
  */
-static void format_header_field(git_buf *out, const char *field, const char *content)
+static int format_header_field(git_buf *out, const char *field, const char *content)
 {
        const char *lf;
 
-       assert(out && field && content);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(field);
+       GIT_ASSERT_ARG(content);
 
        git_buf_puts(out, field);
        git_buf_putc(out, ' ');
@@ -876,6 +885,8 @@ static void format_header_field(git_buf *out, const char *field, const char *con
 
        git_buf_puts(out, content);
        git_buf_putc(out, '\n');
+
+       return git_buf_oom(out) ? -1 : 0;
 }
 
 static const git_oid *commit_parent_from_commit(size_t n, void *payload)
@@ -926,7 +937,9 @@ int git_commit_create_with_signature(
 
        if (signature != NULL) {
                field = signature_field ? signature_field : "gpgsig";
-               format_header_field(&commit, field, signature);
+
+               if ((error = format_header_field(&commit, field, signature)) < 0)
+                       goto cleanup;
        }
 
        git_buf_puts(&commit, header_end);
diff --git a/src/commit_graph.c b/src/commit_graph.c
new file mode 100644 (file)
index 0000000..f663fc5
--- /dev/null
@@ -0,0 +1,1209 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "commit_graph.h"
+
+#include "array.h"
+#include "filebuf.h"
+#include "futils.h"
+#include "hash.h"
+#include "oidarray.h"
+#include "oidmap.h"
+#include "pack.h"
+#include "repository.h"
+#include "revwalk.h"
+
+#define GIT_COMMIT_GRAPH_MISSING_PARENT 0x70000000
+#define GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX 0x3FFFFFFF
+#define GIT_COMMIT_GRAPH_GENERATION_NUMBER_INFINITY 0xFFFFFFFF
+
+#define COMMIT_GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
+#define COMMIT_GRAPH_VERSION 1
+#define COMMIT_GRAPH_OBJECT_ID_VERSION 1
+struct git_commit_graph_header {
+       uint32_t signature;
+       uint8_t version;
+       uint8_t object_id_version;
+       uint8_t chunks;
+       uint8_t base_graph_files;
+};
+
+#define COMMIT_GRAPH_OID_FANOUT_ID 0x4f494446        /* "OIDF" */
+#define COMMIT_GRAPH_OID_LOOKUP_ID 0x4f49444c        /* "OIDL" */
+#define COMMIT_GRAPH_COMMIT_DATA_ID 0x43444154       /* "CDAT" */
+#define COMMIT_GRAPH_EXTRA_EDGE_LIST_ID 0x45444745    /* "EDGE" */
+#define COMMIT_GRAPH_BLOOM_FILTER_INDEX_ID 0x42494458 /* "BIDX" */
+#define COMMIT_GRAPH_BLOOM_FILTER_DATA_ID 0x42444154  /* "BDAT" */
+
+struct git_commit_graph_chunk {
+       off64_t offset;
+       size_t length;
+};
+
+typedef git_array_t(size_t) parent_index_array_t;
+
+struct packed_commit {
+       size_t index;
+       git_oid sha1;
+       git_oid tree_oid;
+       uint32_t generation;
+       git_time_t commit_time;
+       git_array_oid_t parents;
+       parent_index_array_t parent_indices;
+};
+
+static void packed_commit_free(struct packed_commit *p)
+{
+       if (!p)
+               return;
+
+       git_array_clear(p->parents);
+       git_array_clear(p->parent_indices);
+       git__free(p);
+}
+
+static struct packed_commit *packed_commit_new(git_commit *commit)
+{
+       unsigned int i, parentcount = git_commit_parentcount(commit);
+       struct packed_commit *p = git__calloc(1, sizeof(struct packed_commit));
+       if (!p)
+               goto cleanup;
+
+       git_array_init_to_size(p->parents, parentcount);
+       if (parentcount && !p->parents.ptr)
+               goto cleanup;
+
+       if (git_oid_cpy(&p->sha1, git_commit_id(commit)) < 0)
+               goto cleanup;
+       if (git_oid_cpy(&p->tree_oid, git_commit_tree_id(commit)) < 0)
+               goto cleanup;
+       p->commit_time = git_commit_time(commit);
+
+       for (i = 0; i < parentcount; ++i) {
+               git_oid *parent_id = git_array_alloc(p->parents);
+               if (!parent_id)
+                       goto cleanup;
+               if (git_oid_cpy(parent_id, git_commit_parent_id(commit, i)) < 0)
+                       goto cleanup;
+       }
+
+       return p;
+
+cleanup:
+       packed_commit_free(p);
+       return NULL;
+}
+
+typedef int (*commit_graph_write_cb)(const char *buf, size_t size, void *cb_data);
+
+static int commit_graph_error(const char *message)
+{
+       git_error_set(GIT_ERROR_ODB, "invalid commit-graph file - %s", message);
+       return -1;
+}
+
+static int commit_graph_parse_oid_fanout(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               struct git_commit_graph_chunk *chunk_oid_fanout)
+{
+       uint32_t i, nr;
+       if (chunk_oid_fanout->offset == 0)
+               return commit_graph_error("missing OID Fanout chunk");
+       if (chunk_oid_fanout->length == 0)
+               return commit_graph_error("empty OID Fanout chunk");
+       if (chunk_oid_fanout->length != 256 * 4)
+               return commit_graph_error("OID Fanout chunk has wrong length");
+
+       file->oid_fanout = (const uint32_t *)(data + chunk_oid_fanout->offset);
+       nr = 0;
+       for (i = 0; i < 256; ++i) {
+               uint32_t n = ntohl(file->oid_fanout[i]);
+               if (n < nr)
+                       return commit_graph_error("index is non-monotonic");
+               nr = n;
+       }
+       file->num_commits = nr;
+       return 0;
+}
+
+static int commit_graph_parse_oid_lookup(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               struct git_commit_graph_chunk *chunk_oid_lookup)
+{
+       uint32_t i;
+       git_oid *oid, *prev_oid, zero_oid = {{0}};
+
+       if (chunk_oid_lookup->offset == 0)
+               return commit_graph_error("missing OID Lookup chunk");
+       if (chunk_oid_lookup->length == 0)
+               return commit_graph_error("empty OID Lookup chunk");
+       if (chunk_oid_lookup->length != file->num_commits * GIT_OID_RAWSZ)
+               return commit_graph_error("OID Lookup chunk has wrong length");
+
+       file->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset);
+       prev_oid = &zero_oid;
+       for (i = 0; i < file->num_commits; ++i, ++oid) {
+               if (git_oid_cmp(prev_oid, oid) >= 0)
+                       return commit_graph_error("OID Lookup index is non-monotonic");
+               prev_oid = oid;
+       }
+
+       return 0;
+}
+
+static int commit_graph_parse_commit_data(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               struct git_commit_graph_chunk *chunk_commit_data)
+{
+       if (chunk_commit_data->offset == 0)
+               return commit_graph_error("missing Commit Data chunk");
+       if (chunk_commit_data->length == 0)
+               return commit_graph_error("empty Commit Data chunk");
+       if (chunk_commit_data->length != file->num_commits * (GIT_OID_RAWSZ + 16))
+               return commit_graph_error("Commit Data chunk has wrong length");
+
+       file->commit_data = data + chunk_commit_data->offset;
+
+       return 0;
+}
+
+static int commit_graph_parse_extra_edge_list(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               struct git_commit_graph_chunk *chunk_extra_edge_list)
+{
+       if (chunk_extra_edge_list->length == 0)
+               return 0;
+       if (chunk_extra_edge_list->length % 4 != 0)
+               return commit_graph_error("malformed Extra Edge List chunk");
+
+       file->extra_edge_list = data + chunk_extra_edge_list->offset;
+       file->num_extra_edge_list = chunk_extra_edge_list->length / 4;
+
+       return 0;
+}
+
+int git_commit_graph_file_parse(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               size_t size)
+{
+       struct git_commit_graph_header *hdr;
+       const unsigned char *chunk_hdr;
+       struct git_commit_graph_chunk *last_chunk;
+       uint32_t i;
+       off64_t last_chunk_offset, chunk_offset, trailer_offset;
+       git_oid cgraph_checksum = {{0}};
+       int error;
+       struct git_commit_graph_chunk chunk_oid_fanout = {0}, chunk_oid_lookup = {0},
+                                     chunk_commit_data = {0}, chunk_extra_edge_list = {0},
+                                     chunk_unsupported = {0};
+
+       GIT_ASSERT_ARG(file);
+
+       if (size < sizeof(struct git_commit_graph_header) + GIT_OID_RAWSZ)
+               return commit_graph_error("commit-graph is too short");
+
+       hdr = ((struct git_commit_graph_header *)data);
+
+       if (hdr->signature != htonl(COMMIT_GRAPH_SIGNATURE) || hdr->version != COMMIT_GRAPH_VERSION
+           || hdr->object_id_version != COMMIT_GRAPH_OBJECT_ID_VERSION) {
+               return commit_graph_error("unsupported commit-graph version");
+       }
+       if (hdr->chunks == 0)
+               return commit_graph_error("no chunks in commit-graph");
+
+       /*
+        * The very first chunk's offset should be after the header, all the chunk
+        * headers, and a special zero chunk.
+        */
+       last_chunk_offset = sizeof(struct git_commit_graph_header) + (1 + hdr->chunks) * 12;
+       trailer_offset = size - GIT_OID_RAWSZ;
+       if (trailer_offset < last_chunk_offset)
+               return commit_graph_error("wrong commit-graph size");
+       git_oid_cpy(&file->checksum, (git_oid *)(data + trailer_offset));
+
+       if (git_hash_buf(&cgraph_checksum, data, (size_t)trailer_offset) < 0)
+               return commit_graph_error("could not calculate signature");
+       if (!git_oid_equal(&cgraph_checksum, &file->checksum))
+               return commit_graph_error("index signature mismatch");
+
+       chunk_hdr = data + sizeof(struct git_commit_graph_header);
+       last_chunk = NULL;
+       for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) {
+               chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32
+                               | ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8))));
+               if (chunk_offset < last_chunk_offset)
+                       return commit_graph_error("chunks are non-monotonic");
+               if (chunk_offset >= trailer_offset)
+                       return commit_graph_error("chunks extend beyond the trailer");
+               if (last_chunk != NULL)
+                       last_chunk->length = (size_t)(chunk_offset - last_chunk_offset);
+               last_chunk_offset = chunk_offset;
+
+               switch (ntohl(*((uint32_t *)(chunk_hdr + 0)))) {
+               case COMMIT_GRAPH_OID_FANOUT_ID:
+                       chunk_oid_fanout.offset = last_chunk_offset;
+                       last_chunk = &chunk_oid_fanout;
+                       break;
+
+               case COMMIT_GRAPH_OID_LOOKUP_ID:
+                       chunk_oid_lookup.offset = last_chunk_offset;
+                       last_chunk = &chunk_oid_lookup;
+                       break;
+
+               case COMMIT_GRAPH_COMMIT_DATA_ID:
+                       chunk_commit_data.offset = last_chunk_offset;
+                       last_chunk = &chunk_commit_data;
+                       break;
+
+               case COMMIT_GRAPH_EXTRA_EDGE_LIST_ID:
+                       chunk_extra_edge_list.offset = last_chunk_offset;
+                       last_chunk = &chunk_extra_edge_list;
+                       break;
+
+               case COMMIT_GRAPH_BLOOM_FILTER_INDEX_ID:
+               case COMMIT_GRAPH_BLOOM_FILTER_DATA_ID:
+                       chunk_unsupported.offset = last_chunk_offset;
+                       last_chunk = &chunk_unsupported;
+                       break;
+
+               default:
+                       return commit_graph_error("unrecognized chunk ID");
+               }
+       }
+       last_chunk->length = (size_t)(trailer_offset - last_chunk_offset);
+
+       error = commit_graph_parse_oid_fanout(file, data, &chunk_oid_fanout);
+       if (error < 0)
+               return error;
+       error = commit_graph_parse_oid_lookup(file, data, &chunk_oid_lookup);
+       if (error < 0)
+               return error;
+       error = commit_graph_parse_commit_data(file, data, &chunk_commit_data);
+       if (error < 0)
+               return error;
+       error = commit_graph_parse_extra_edge_list(file, data, &chunk_extra_edge_list);
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file)
+{
+       git_commit_graph *cgraph = NULL;
+       int error = 0;
+
+       GIT_ASSERT_ARG(cgraph_out);
+       GIT_ASSERT_ARG(objects_dir);
+
+       cgraph = git__calloc(1, sizeof(git_commit_graph));
+       GIT_ERROR_CHECK_ALLOC(cgraph);
+
+       error = git_buf_joinpath(&cgraph->filename, objects_dir, "info/commit-graph");
+       if (error < 0)
+               goto error;
+
+       if (open_file) {
+               error = git_commit_graph_file_open(&cgraph->file, git_buf_cstr(&cgraph->filename));
+               if (error < 0)
+                       goto error;
+               cgraph->checked = 1;
+       }
+
+       *cgraph_out = cgraph;
+       return 0;
+
+error:
+       git_commit_graph_free(cgraph);
+       return error;
+}
+
+int git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir)
+{
+       return git_commit_graph_new(cgraph_out, objects_dir, true);
+}
+
+int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path)
+{
+       git_commit_graph_file *file;
+       git_file fd = -1;
+       size_t cgraph_size;
+       struct stat st;
+       int error;
+
+       /* TODO: properly open the file without access time using O_NOATIME */
+       fd = git_futils_open_ro(path);
+       if (fd < 0)
+               return fd;
+
+       if (p_fstat(fd, &st) < 0) {
+               p_close(fd);
+               git_error_set(GIT_ERROR_ODB, "commit-graph file not found - '%s'", path);
+               return GIT_ENOTFOUND;
+       }
+
+       if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)) {
+               p_close(fd);
+               git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path);
+               return GIT_ENOTFOUND;
+       }
+       cgraph_size = (size_t)st.st_size;
+
+       file = git__calloc(1, sizeof(git_commit_graph_file));
+       GIT_ERROR_CHECK_ALLOC(file);
+
+       error = git_futils_mmap_ro(&file->graph_map, fd, 0, cgraph_size);
+       p_close(fd);
+       if (error < 0) {
+               git_commit_graph_file_free(file);
+               return error;
+       }
+
+       if ((error = git_commit_graph_file_parse(file, file->graph_map.data, cgraph_size)) < 0) {
+               git_commit_graph_file_free(file);
+               return error;
+       }
+
+       *file_out = file;
+       return 0;
+}
+
+int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph *cgraph)
+{
+       if (!cgraph->checked) {
+               int error = 0;
+               git_commit_graph_file *result = NULL;
+
+               /* We only check once, no matter the result. */
+               cgraph->checked = 1;
+
+               /* Best effort */
+               error = git_commit_graph_file_open(&result, git_buf_cstr(&cgraph->filename));
+
+               if (error < 0)
+                       return error;
+
+               cgraph->file = result;
+       }
+       if (!cgraph->file)
+               return GIT_ENOTFOUND;
+
+       *file_out = cgraph->file;
+       return 0;
+}
+
+void git_commit_graph_refresh(git_commit_graph *cgraph)
+{
+       if (!cgraph->checked)
+               return;
+
+       if (cgraph->file
+           && git_commit_graph_file_needs_refresh(cgraph->file, git_buf_cstr(&cgraph->filename))) {
+               /* We just free the commit graph. The next time it is requested, it will be
+                * re-loaded. */
+               git_commit_graph_file_free(cgraph->file);
+               cgraph->file = NULL;
+       }
+       /* Force a lazy re-check next time it is needed. */
+       cgraph->checked = 0;
+}
+
+static int git_commit_graph_entry_get_byindex(
+               git_commit_graph_entry *e,
+               const git_commit_graph_file *file,
+               size_t pos)
+{
+       const unsigned char *commit_data;
+
+       GIT_ASSERT_ARG(e);
+       GIT_ASSERT_ARG(file);
+
+       if (pos >= file->num_commits) {
+               git_error_set(GIT_ERROR_INVALID, "commit index %zu does not exist", pos);
+               return GIT_ENOTFOUND;
+       }
+
+       commit_data = file->commit_data + pos * (GIT_OID_RAWSZ + 4 * sizeof(uint32_t));
+       git_oid_cpy(&e->tree_oid, (const git_oid *)commit_data);
+       e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ)));
+       e->parent_indices[1] = ntohl(
+                       *((uint32_t *)(commit_data + GIT_OID_RAWSZ + sizeof(uint32_t))));
+       e->parent_count = (e->parent_indices[0] != GIT_COMMIT_GRAPH_MISSING_PARENT)
+                       + (e->parent_indices[1] != GIT_COMMIT_GRAPH_MISSING_PARENT);
+       e->generation = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 2 * sizeof(uint32_t))));
+       e->commit_time = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 3 * sizeof(uint32_t))));
+
+       e->commit_time |= (e->generation & UINT64_C(0x3)) << UINT64_C(32);
+       e->generation >>= 2u;
+       if (e->parent_indices[1] & 0x80000000u) {
+               uint32_t extra_edge_list_pos = e->parent_indices[1] & 0x7fffffff;
+
+               /* Make sure we're not being sent out of bounds */
+               if (extra_edge_list_pos >= file->num_extra_edge_list) {
+                       git_error_set(GIT_ERROR_INVALID,
+                                     "commit %u does not exist",
+                                     extra_edge_list_pos);
+                       return GIT_ENOTFOUND;
+               }
+
+               e->extra_parents_index = extra_edge_list_pos;
+               while (extra_edge_list_pos < file->num_extra_edge_list
+                      && (ntohl(*(
+                                          (uint32_t *)(file->extra_edge_list
+                                                       + extra_edge_list_pos * sizeof(uint32_t))))
+                          & 0x80000000u)
+                                      == 0) {
+                       extra_edge_list_pos++;
+                       e->parent_count++;
+               }
+       }
+       git_oid_cpy(&e->sha1, &file->oid_lookup[pos]);
+       return 0;
+}
+
+bool git_commit_graph_file_needs_refresh(const git_commit_graph_file *file, const char *path)
+{
+       git_file fd = -1;
+       struct stat st;
+       ssize_t bytes_read;
+       git_oid cgraph_checksum = {{0}};
+
+       /* TODO: properly open the file without access time using O_NOATIME */
+       fd = git_futils_open_ro(path);
+       if (fd < 0)
+               return true;
+
+       if (p_fstat(fd, &st) < 0) {
+               p_close(fd);
+               return true;
+       }
+
+       if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)
+           || (size_t)st.st_size != file->graph_map.len) {
+               p_close(fd);
+               return true;
+       }
+
+       bytes_read = p_pread(fd, cgraph_checksum.id, GIT_OID_RAWSZ, st.st_size - GIT_OID_RAWSZ);
+       p_close(fd);
+       if (bytes_read != GIT_OID_RAWSZ)
+               return true;
+
+       return !git_oid_equal(&cgraph_checksum, &file->checksum);
+}
+
+int git_commit_graph_entry_find(
+               git_commit_graph_entry *e,
+               const git_commit_graph_file *file,
+               const git_oid *short_oid,
+               size_t len)
+{
+       int pos, found = 0;
+       uint32_t hi, lo;
+       const git_oid *current = NULL;
+
+       GIT_ASSERT_ARG(e);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(short_oid);
+
+       hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]);
+       lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1]));
+
+       pos = git_pack__lookup_sha1(file->oid_lookup, GIT_OID_RAWSZ, lo, hi, short_oid->id);
+
+       if (pos >= 0) {
+               /* An object matching exactly the oid was found */
+               found = 1;
+               current = file->oid_lookup + pos;
+       } else {
+               /* No object was found */
+               /* pos refers to the object with the "closest" oid to short_oid */
+               pos = -1 - pos;
+               if (pos < (int)file->num_commits) {
+                       current = file->oid_lookup + pos;
+
+                       if (!git_oid_ncmp(short_oid, current, len))
+                               found = 1;
+               }
+       }
+
+       if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)file->num_commits) {
+               /* Check for ambiguousity */
+               const git_oid *next = current + 1;
+
+               if (!git_oid_ncmp(short_oid, next, len)) {
+                       found = 2;
+               }
+       }
+
+       if (!found)
+               return git_odb__error_notfound(
+                               "failed to find offset for commit-graph index entry", short_oid, len);
+       if (found > 1)
+               return git_odb__error_ambiguous(
+                               "found multiple offsets for commit-graph index entry");
+
+       return git_commit_graph_entry_get_byindex(e, file, pos);
+}
+
+int git_commit_graph_entry_parent(
+               git_commit_graph_entry *parent,
+               const git_commit_graph_file *file,
+               const git_commit_graph_entry *entry,
+               size_t n)
+{
+       GIT_ASSERT_ARG(parent);
+       GIT_ASSERT_ARG(file);
+
+       if (n >= entry->parent_count) {
+               git_error_set(GIT_ERROR_INVALID, "parent index %zu does not exist", n);
+               return GIT_ENOTFOUND;
+       }
+
+       if (n == 0 || (n == 1 && entry->parent_count == 2))
+               return git_commit_graph_entry_get_byindex(parent, file, entry->parent_indices[n]);
+
+       return git_commit_graph_entry_get_byindex(
+                       parent,
+                       file,
+                       ntohl(
+                                       *(uint32_t *)(file->extra_edge_list
+                                                     + (entry->extra_parents_index + n - 1)
+                                                                     * sizeof(uint32_t)))
+                                       & 0x7fffffff);
+}
+
+int git_commit_graph_file_close(git_commit_graph_file *file)
+{
+       GIT_ASSERT_ARG(file);
+
+       if (file->graph_map.data)
+               git_futils_mmap_free(&file->graph_map);
+
+       return 0;
+}
+
+void git_commit_graph_free(git_commit_graph *cgraph)
+{
+       if (!cgraph)
+               return;
+
+       git_buf_dispose(&cgraph->filename);
+       git_commit_graph_file_free(cgraph->file);
+       git__free(cgraph);
+}
+
+void git_commit_graph_file_free(git_commit_graph_file *file)
+{
+       if (!file)
+               return;
+
+       git_commit_graph_file_close(file);
+       git__free(file);
+}
+
+static int packed_commit__cmp(const void *a_, const void *b_)
+{
+       const struct packed_commit *a = a_;
+       const struct packed_commit *b = b_;
+       return git_oid_cmp(&a->sha1, &b->sha1);
+}
+
+int git_commit_graph_writer_new(git_commit_graph_writer **out, const char *objects_info_dir)
+{
+       git_commit_graph_writer *w = git__calloc(1, sizeof(git_commit_graph_writer));
+       GIT_ERROR_CHECK_ALLOC(w);
+
+       if (git_buf_sets(&w->objects_info_dir, objects_info_dir) < 0) {
+               git__free(w);
+               return -1;
+       }
+
+       if (git_vector_init(&w->commits, 0, packed_commit__cmp) < 0) {
+               git_buf_dispose(&w->objects_info_dir);
+               git__free(w);
+               return -1;
+       }
+
+       *out = w;
+       return 0;
+}
+
+void git_commit_graph_writer_free(git_commit_graph_writer *w)
+{
+       struct packed_commit *packed_commit;
+       size_t i;
+
+       if (!w)
+               return;
+
+       git_vector_foreach (&w->commits, i, packed_commit)
+               packed_commit_free(packed_commit);
+       git_vector_free(&w->commits);
+       git_buf_dispose(&w->objects_info_dir);
+       git__free(w);
+}
+
+struct object_entry_cb_state {
+       git_repository *repo;
+       git_odb *db;
+       git_vector *commits;
+};
+
+static int object_entry__cb(const git_oid *id, void *data)
+{
+       struct object_entry_cb_state *state = (struct object_entry_cb_state *)data;
+       git_commit *commit = NULL;
+       struct packed_commit *packed_commit = NULL;
+       size_t header_len;
+       git_object_t header_type;
+       int error = 0;
+
+       error = git_odb_read_header(&header_len, &header_type, state->db, id);
+       if (error < 0)
+               return error;
+
+       if (header_type != GIT_OBJECT_COMMIT)
+               return 0;
+
+       error = git_commit_lookup(&commit, state->repo, id);
+       if (error < 0)
+               return error;
+
+       packed_commit = packed_commit_new(commit);
+       git_commit_free(commit);
+       GIT_ERROR_CHECK_ALLOC(packed_commit);
+
+       error = git_vector_insert(state->commits, packed_commit);
+       if (error < 0) {
+               packed_commit_free(packed_commit);
+               return error;
+       }
+
+       return 0;
+}
+
+int git_commit_graph_writer_add_index_file(
+               git_commit_graph_writer *w,
+               git_repository *repo,
+               const char *idx_path)
+{
+       int error;
+       struct git_pack_file *p = NULL;
+       struct object_entry_cb_state state = {0};
+       state.repo = repo;
+       state.commits = &w->commits;
+
+       error = git_repository_odb(&state.db, repo);
+       if (error < 0)
+               goto cleanup;
+
+       error = git_mwindow_get_pack(&p, idx_path);
+       if (error < 0)
+               goto cleanup;
+
+       error = git_pack_foreach_entry(p, object_entry__cb, &state);
+       if (error < 0)
+               goto cleanup;
+
+cleanup:
+       if (p)
+               git_mwindow_put_pack(p);
+       git_odb_free(state.db);
+       return error;
+}
+
+int git_commit_graph_writer_add_revwalk(git_commit_graph_writer *w, git_revwalk *walk)
+{
+       int error;
+       git_oid id;
+       git_repository *repo = git_revwalk_repository(walk);
+       git_commit *commit;
+       struct packed_commit *packed_commit;
+
+       while ((git_revwalk_next(&id, walk)) == 0) {
+               error = git_commit_lookup(&commit, repo, &id);
+               if (error < 0)
+                       return error;
+
+               packed_commit = packed_commit_new(commit);
+               git_commit_free(commit);
+               GIT_ERROR_CHECK_ALLOC(packed_commit);
+
+               error = git_vector_insert(&w->commits, packed_commit);
+               if (error < 0) {
+                       packed_commit_free(packed_commit);
+                       return error;
+               }
+       }
+
+       return 0;
+}
+
+enum generation_number_commit_state {
+       GENERATION_NUMBER_COMMIT_STATE_UNVISITED = 0,
+       GENERATION_NUMBER_COMMIT_STATE_ADDED = 1,
+       GENERATION_NUMBER_COMMIT_STATE_EXPANDED = 2,
+       GENERATION_NUMBER_COMMIT_STATE_VISITED = 3,
+};
+
+static int compute_generation_numbers(git_vector *commits)
+{
+       git_array_t(size_t) index_stack = GIT_ARRAY_INIT;
+       size_t i, j;
+       size_t *parent_idx;
+       enum generation_number_commit_state *commit_states = NULL;
+       struct packed_commit *child_packed_commit;
+       git_oidmap *packed_commit_map = NULL;
+       int error = 0;
+
+       /* First populate the parent indices fields */
+       error = git_oidmap_new(&packed_commit_map);
+       if (error < 0)
+               goto cleanup;
+       git_vector_foreach (commits, i, child_packed_commit) {
+               child_packed_commit->index = i;
+               error = git_oidmap_set(
+                               packed_commit_map, &child_packed_commit->sha1, child_packed_commit);
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       git_vector_foreach (commits, i, child_packed_commit) {
+               size_t parent_i, *parent_idx_ptr;
+               struct packed_commit *parent_packed_commit;
+               git_oid *parent_id;
+               git_array_init_to_size(
+                               child_packed_commit->parent_indices,
+                               git_array_size(child_packed_commit->parents));
+               if (git_array_size(child_packed_commit->parents)
+                   && !child_packed_commit->parent_indices.ptr) {
+                       error = -1;
+                       goto cleanup;
+               }
+               git_array_foreach (child_packed_commit->parents, parent_i, parent_id) {
+                       parent_packed_commit = git_oidmap_get(packed_commit_map, parent_id);
+                       if (!parent_packed_commit) {
+                               git_error_set(GIT_ERROR_ODB,
+                                             "parent commit %s not found in commit graph",
+                                             git_oid_tostr_s(parent_id));
+                               error = GIT_ENOTFOUND;
+                               goto cleanup;
+                       }
+                       parent_idx_ptr = git_array_alloc(child_packed_commit->parent_indices);
+                       if (!parent_idx_ptr) {
+                               error = -1;
+                               goto cleanup;
+                       }
+                       *parent_idx_ptr = parent_packed_commit->index;
+               }
+       }
+
+       /*
+        * We copy all the commits to the stack and then during visitation,
+        * each node can be added up to two times to the stack.
+        */
+       git_array_init_to_size(index_stack, 3 * git_vector_length(commits));
+       if (!index_stack.ptr) {
+               error = -1;
+               goto cleanup;
+       }
+
+       commit_states = (enum generation_number_commit_state *)git__calloc(
+                       git_vector_length(commits), sizeof(enum generation_number_commit_state));
+       if (!commit_states) {
+               error = -1;
+               goto cleanup;
+       }
+
+       /*
+        * Perform a Post-Order traversal so that all parent nodes are fully
+        * visited before the child node.
+        */
+       git_vector_foreach (commits, i, child_packed_commit)
+               *(size_t *)git_array_alloc(index_stack) = i;
+
+       while (git_array_size(index_stack)) {
+               size_t *index_ptr = git_array_pop(index_stack);
+               i = *index_ptr;
+               child_packed_commit = git_vector_get(commits, i);
+
+               if (commit_states[i] == GENERATION_NUMBER_COMMIT_STATE_VISITED) {
+                       /* This commit has already been fully visited. */
+                       continue;
+               }
+               if (commit_states[i] == GENERATION_NUMBER_COMMIT_STATE_EXPANDED) {
+                       /* All of the commits parents have been visited. */
+                       child_packed_commit->generation = 0;
+                       git_array_foreach (child_packed_commit->parent_indices, j, parent_idx) {
+                               struct packed_commit *parent = git_vector_get(commits, *parent_idx);
+                               if (child_packed_commit->generation < parent->generation)
+                                       child_packed_commit->generation = parent->generation;
+                       }
+                       if (child_packed_commit->generation
+                           < GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX) {
+                               ++child_packed_commit->generation;
+                       }
+                       commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_VISITED;
+                       continue;
+               }
+
+               /*
+                * This is the first time we see this commit. We need
+                * to visit all its parents before we can fully visit
+                * it.
+                */
+               if (git_array_size(child_packed_commit->parent_indices) == 0) {
+                       /*
+                        * Special case: if the commit has no parents, there's
+                        * no need to add it to the stack just to immediately
+                        * remove it.
+                        */
+                       commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_VISITED;
+                       child_packed_commit->generation = 1;
+                       continue;
+               }
+
+               /*
+                * Add this current commit again so that it is visited
+                * again once all its children have been visited.
+                */
+               *(size_t *)git_array_alloc(index_stack) = i;
+               git_array_foreach (child_packed_commit->parent_indices, j, parent_idx) {
+                       if (commit_states[*parent_idx]
+                           != GENERATION_NUMBER_COMMIT_STATE_UNVISITED) {
+                               /* This commit has already been considered. */
+                               continue;
+                       }
+
+                       commit_states[*parent_idx] = GENERATION_NUMBER_COMMIT_STATE_ADDED;
+                       *(size_t *)git_array_alloc(index_stack) = *parent_idx;
+               }
+               commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_EXPANDED;
+       }
+
+cleanup:
+       git_oidmap_free(packed_commit_map);
+       git__free(commit_states);
+       git_array_clear(index_stack);
+
+       return error;
+}
+
+static int write_offset(off64_t offset, commit_graph_write_cb write_cb, void *cb_data)
+{
+       int error;
+       uint32_t word;
+
+       word = htonl((uint32_t)((offset >> 32) & 0xffffffffu));
+       error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+       word = htonl((uint32_t)((offset >> 0) & 0xffffffffu));
+       error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+static int write_chunk_header(
+               int chunk_id,
+               off64_t offset,
+               commit_graph_write_cb write_cb,
+               void *cb_data)
+{
+       uint32_t word = htonl(chunk_id);
+       int error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+       return write_offset(offset, write_cb, cb_data);
+}
+
+static int commit_graph_write_buf(const char *buf, size_t size, void *data)
+{
+       git_buf *b = (git_buf *)data;
+       return git_buf_put(b, buf, size);
+}
+
+struct commit_graph_write_hash_context {
+       commit_graph_write_cb write_cb;
+       void *cb_data;
+       git_hash_ctx *ctx;
+};
+
+static int commit_graph_write_hash(const char *buf, size_t size, void *data)
+{
+       struct commit_graph_write_hash_context *ctx = data;
+       int error;
+
+       error = git_hash_update(ctx->ctx, buf, size);
+       if (error < 0)
+               return error;
+
+       return ctx->write_cb(buf, size, ctx->cb_data);
+}
+
+static void packed_commit_free_dup(void *packed_commit)
+{
+       packed_commit_free(packed_commit);
+}
+
+static int commit_graph_write(
+               git_commit_graph_writer *w,
+               commit_graph_write_cb write_cb,
+               void *cb_data)
+{
+       int error = 0;
+       size_t i;
+       struct packed_commit *packed_commit;
+       struct git_commit_graph_header hdr = {0};
+       uint32_t oid_fanout_count;
+       uint32_t extra_edge_list_count;
+       uint32_t oid_fanout[256];
+       off64_t offset;
+       git_buf oid_lookup = GIT_BUF_INIT, commit_data = GIT_BUF_INIT,
+               extra_edge_list = GIT_BUF_INIT;
+       git_oid cgraph_checksum = {{0}};
+       git_hash_ctx ctx;
+       struct commit_graph_write_hash_context hash_cb_data = {0};
+
+       hdr.signature = htonl(COMMIT_GRAPH_SIGNATURE);
+       hdr.version = COMMIT_GRAPH_VERSION;
+       hdr.object_id_version = COMMIT_GRAPH_OBJECT_ID_VERSION;
+       hdr.chunks = 0;
+       hdr.base_graph_files = 0;
+       hash_cb_data.write_cb = write_cb;
+       hash_cb_data.cb_data = cb_data;
+       hash_cb_data.ctx = &ctx;
+
+       error = git_hash_ctx_init(&ctx);
+       if (error < 0)
+               return error;
+       cb_data = &hash_cb_data;
+       write_cb = commit_graph_write_hash;
+
+       /* Sort the commits. */
+       git_vector_sort(&w->commits);
+       git_vector_uniq(&w->commits, packed_commit_free_dup);
+       error = compute_generation_numbers(&w->commits);
+       if (error < 0)
+               goto cleanup;
+
+       /* Fill the OID Fanout table. */
+       oid_fanout_count = 0;
+       for (i = 0; i < 256; i++) {
+               while (oid_fanout_count < git_vector_length(&w->commits) &&
+                      (packed_commit = (struct packed_commit *)git_vector_get(&w->commits, oid_fanout_count)) &&
+                      packed_commit->sha1.id[0] <= i)
+                       ++oid_fanout_count;
+               oid_fanout[i] = htonl(oid_fanout_count);
+       }
+
+       /* Fill the OID Lookup table. */
+       git_vector_foreach (&w->commits, i, packed_commit) {
+               error = git_buf_put(&oid_lookup,
+                       (const char *)&packed_commit->sha1, sizeof(git_oid));
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /* Fill the Commit Data and Extra Edge List tables. */
+       extra_edge_list_count = 0;
+       git_vector_foreach (&w->commits, i, packed_commit) {
+               uint64_t commit_time;
+               uint32_t generation;
+               uint32_t word;
+               size_t *packed_index;
+               unsigned int parentcount = (unsigned int)git_array_size(packed_commit->parents);
+
+               error = git_buf_put(&commit_data,
+                               (const char *)&packed_commit->tree_oid,
+                               sizeof(git_oid));
+               if (error < 0)
+                       goto cleanup;
+
+               if (parentcount == 0) {
+                       word = htonl(GIT_COMMIT_GRAPH_MISSING_PARENT);
+               } else {
+                       packed_index = git_array_get(packed_commit->parent_indices, 0);
+                       word = htonl((uint32_t)*packed_index);
+               }
+               error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+
+               if (parentcount < 2) {
+                       word = htonl(GIT_COMMIT_GRAPH_MISSING_PARENT);
+               } else if (parentcount == 2) {
+                       packed_index = git_array_get(packed_commit->parent_indices, 1);
+                       word = htonl((uint32_t)*packed_index);
+               } else {
+                       word = htonl(0x80000000u | extra_edge_list_count);
+               }
+               error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+
+               if (parentcount > 2) {
+                       unsigned int parent_i;
+                       for (parent_i = 1; parent_i < parentcount; ++parent_i) {
+                               packed_index = git_array_get(
+                                       packed_commit->parent_indices, parent_i);
+                               word = htonl((uint32_t)(*packed_index | (parent_i + 1 == parentcount ? 0x80000000u : 0)));
+
+                               error = git_buf_put(&extra_edge_list,
+                                               (const char *)&word,
+                                               sizeof(word));
+                               if (error < 0)
+                                       goto cleanup;
+                       }
+                       extra_edge_list_count += parentcount - 1;
+               }
+
+               generation = packed_commit->generation;
+               commit_time = (uint64_t)packed_commit->commit_time;
+               if (generation > GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX)
+                       generation = GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX;
+               word = ntohl((uint32_t)((generation << 2) | ((commit_time >> 32ull) & 0x3ull)));
+               error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+               word = ntohl((uint32_t)(commit_time & 0xffffffffull));
+               error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /* Write the header. */
+       hdr.chunks = 3;
+       if (git_buf_len(&extra_edge_list) > 0)
+               hdr.chunks++;
+       error = write_cb((const char *)&hdr, sizeof(hdr), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Write the chunk headers. */
+       offset = sizeof(hdr) + (hdr.chunks + 1) * 12;
+       error = write_chunk_header(COMMIT_GRAPH_OID_FANOUT_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += sizeof(oid_fanout);
+       error = write_chunk_header(COMMIT_GRAPH_OID_LOOKUP_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += git_buf_len(&oid_lookup);
+       error = write_chunk_header(COMMIT_GRAPH_COMMIT_DATA_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += git_buf_len(&commit_data);
+       if (git_buf_len(&extra_edge_list) > 0) {
+               error = write_chunk_header(
+                               COMMIT_GRAPH_EXTRA_EDGE_LIST_ID, offset, write_cb, cb_data);
+               if (error < 0)
+                       goto cleanup;
+               offset += git_buf_len(&extra_edge_list);
+       }
+       error = write_chunk_header(0, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Write all the chunks. */
+       error = write_cb((const char *)oid_fanout, sizeof(oid_fanout), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&oid_lookup), git_buf_len(&oid_lookup), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&commit_data), git_buf_len(&commit_data), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&extra_edge_list), git_buf_len(&extra_edge_list), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Finalize the checksum and write the trailer. */
+       error = git_hash_final(&cgraph_checksum, &ctx);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb((const char *)&cgraph_checksum, sizeof(cgraph_checksum), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+cleanup:
+       git_buf_dispose(&oid_lookup);
+       git_buf_dispose(&commit_data);
+       git_buf_dispose(&extra_edge_list);
+       git_hash_ctx_cleanup(&ctx);
+       return error;
+}
+
+static int commit_graph_write_filebuf(const char *buf, size_t size, void *data)
+{
+       git_filebuf *f = (git_filebuf *)data;
+       return git_filebuf_write(f, buf, size);
+}
+
+int git_commit_graph_writer_options_init(
+       git_commit_graph_writer_options *opts,
+       unsigned int version)
+{
+       GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+                       opts,
+                       version,
+                       git_commit_graph_writer_options,
+                       GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT);
+       return 0;
+}
+
+int git_commit_graph_writer_commit(
+               git_commit_graph_writer *w,
+               git_commit_graph_writer_options *opts)
+{
+       int error;
+       int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER;
+       git_buf commit_graph_path = GIT_BUF_INIT;
+       git_filebuf output = GIT_FILEBUF_INIT;
+
+       /* TODO: support options and fill in defaults. */
+       GIT_UNUSED(opts);
+
+       error = git_buf_joinpath(
+                       &commit_graph_path, git_buf_cstr(&w->objects_info_dir), "commit-graph");
+       if (error < 0)
+               return error;
+
+       if (git_repository__fsync_gitdir)
+               filebuf_flags |= GIT_FILEBUF_FSYNC;
+       error = git_filebuf_open(&output, git_buf_cstr(&commit_graph_path), filebuf_flags, 0644);
+       git_buf_dispose(&commit_graph_path);
+       if (error < 0)
+               return error;
+
+       error = commit_graph_write(w, commit_graph_write_filebuf, &output);
+       if (error < 0) {
+               git_filebuf_cleanup(&output);
+               return error;
+       }
+
+       return git_filebuf_commit(&output);
+}
+
+int git_commit_graph_writer_dump(
+               git_buf *cgraph,
+               git_commit_graph_writer *w,
+               git_commit_graph_writer_options *opts)
+{
+       /* TODO: support options. */
+       GIT_UNUSED(opts);
+       return commit_graph_write(w, commit_graph_write_buf, cgraph);
+}
diff --git a/src/commit_graph.h b/src/commit_graph.h
new file mode 100644 (file)
index 0000000..9d0a827
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_commit_graph_h__
+#define INCLUDE_commit_graph_h__
+
+#include "common.h"
+
+#include "git2/types.h"
+#include "git2/sys/commit_graph.h"
+
+#include "map.h"
+#include "vector.h"
+
+/**
+ * A commit-graph file.
+ *
+ * This file contains metadata about commits, particularly the generation
+ * number for each one. This can help speed up graph operations without
+ * requiring a full graph traversal.
+ *
+ * Support for this feature was added in git 2.19.
+ */
+typedef struct git_commit_graph_file {
+       git_map graph_map;
+
+       /* The OID Fanout table. */
+       const uint32_t *oid_fanout;
+       /* The total number of commits in the graph. */
+       uint32_t num_commits;
+
+       /* The OID Lookup table. */
+       git_oid *oid_lookup;
+
+       /*
+        * The Commit Data table. Each entry contains the OID of the commit followed
+        * by two 8-byte fields in network byte order:
+        * - The indices of the first two parents (32 bits each).
+        * - The generation number (first 30 bits) and commit time in seconds since
+        *   UNIX epoch (34 bits).
+        */
+       const unsigned char *commit_data;
+
+       /*
+        * The Extra Edge List table. Each 4-byte entry is a network byte order index
+        * of one of the i-th (i > 0) parents of commits in the `commit_data` table,
+        * when the commit has more than 2 parents.
+        */
+       const unsigned char *extra_edge_list;
+       /* The number of entries in the Extra Edge List table. Each entry is 4 bytes wide. */
+       size_t num_extra_edge_list;
+
+       /* The trailer of the file. Contains the SHA1-checksum of the whole file. */
+       git_oid checksum;
+} git_commit_graph_file;
+
+/**
+ * An entry in the commit-graph file. Provides a subset of the information that
+ * can be obtained from the commit header.
+ */
+typedef struct git_commit_graph_entry {
+       /* The generation number of the commit within the graph */
+       size_t generation;
+
+       /* Time in seconds from UNIX epoch. */
+       git_time_t commit_time;
+
+       /* The number of parents of the commit. */
+       size_t parent_count;
+
+       /*
+        * The indices of the parent commits within the Commit Data table. The value
+        * of `GIT_COMMIT_GRAPH_MISSING_PARENT` indicates that no parent is in that
+        * position.
+        */
+       size_t parent_indices[2];
+
+       /* The index within the Extra Edge List of any parent after the first two. */
+       size_t extra_parents_index;
+
+       /* The SHA-1 hash of the root tree of the commit. */
+       git_oid tree_oid;
+
+       /* The SHA-1 hash of the requested commit. */
+       git_oid sha1;
+} git_commit_graph_entry;
+
+/* A wrapper for git_commit_graph_file to enable lazy loading in the ODB. */
+struct git_commit_graph {
+       /* The path to the commit-graph file. Something like ".git/objects/info/commit-graph". */
+       git_buf filename;
+
+       /* The underlying commit-graph file. */
+       git_commit_graph_file *file;
+
+       /* Whether the commit-graph file was already checked for validity. */
+       bool checked;
+};
+
+/** Create a new commit-graph, optionally opening the underlying file. */
+int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file);
+
+/** Open and validate a commit-graph file. */
+int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path);
+
+/*
+ * Attempt to get the git_commit_graph's commit-graph file. This object is
+ * still owned by the git_commit_graph. If the repository does not contain a commit graph,
+ * it will return GIT_ENOTFOUND.
+ *
+ * This function is not thread-safe.
+ */
+int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph *cgraph);
+
+/* Marks the commit-graph file as needing a refresh. */
+void git_commit_graph_refresh(git_commit_graph *cgraph);
+
+/*
+ * A writer for `commit-graph` files.
+ */
+struct git_commit_graph_writer {
+       /*
+        * The path of the `objects/info` directory where the `commit-graph` will be
+        * stored.
+        */
+       git_buf objects_info_dir;
+
+       /* The list of packed commits. */
+       git_vector commits;
+};
+
+/*
+ * Returns whether the git_commit_graph_file needs to be reloaded since the
+ * contents of the commit-graph file have changed on disk.
+ */
+bool git_commit_graph_file_needs_refresh(
+               const git_commit_graph_file *file, const char *path);
+
+int git_commit_graph_entry_find(
+               git_commit_graph_entry *e,
+               const git_commit_graph_file *file,
+               const git_oid *short_oid,
+               size_t len);
+int git_commit_graph_entry_parent(
+               git_commit_graph_entry *parent,
+               const git_commit_graph_file *file,
+               const git_commit_graph_entry *entry,
+               size_t n);
+int git_commit_graph_file_close(git_commit_graph_file *cgraph);
+void git_commit_graph_file_free(git_commit_graph_file *cgraph);
+
+/* This is exposed for use in the fuzzers. */
+int git_commit_graph_file_parse(
+               git_commit_graph_file *file,
+               const unsigned char *data,
+               size_t size);
+
+#endif
index 2e103ec2281f4b1b54d3d07e940de15a11f8e0a1..692b1495f51c74d7d9ba9ba78a3a99e8bb22c07b 100644 (file)
 #include "odb.h"
 #include "commit.h"
 
+int git_commit_list_generation_cmp(const void *a, const void *b)
+{
+       uint32_t generation_a = ((git_commit_list_node *) a)->generation;
+       uint32_t generation_b = ((git_commit_list_node *) b)->generation;
+
+       if (!generation_a || !generation_b) {
+               /* Fall back to comparing by timestamps if at least one commit lacks a generation. */
+               return git_commit_list_time_cmp(a, b);
+       }
+
+       if (generation_a < generation_b)
+               return 1;
+       if (generation_a > generation_b)
+               return -1;
+
+       return 0;
+}
+
 int git_commit_list_time_cmp(const void *a, const void *b)
 {
        int64_t time_a = ((git_commit_list_node *) a)->time;
@@ -124,6 +142,7 @@ static int commit_quick_parse(
                return -1;
        }
 
+       node->generation = 0;
        node->time = commit->committer->when.time;
        node->out_degree = (uint16_t) git_array_size(commit->parent_ids);
        node->parents = alloc_parents(walk, node, node->out_degree);
@@ -143,11 +162,38 @@ static int commit_quick_parse(
 int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit)
 {
        git_odb_object *obj;
+       git_commit_graph_file *cgraph_file = NULL;
        int error;
 
        if (commit->parsed)
                return 0;
 
+       /* Let's try to use the commit graph first. */
+       git_odb__get_commit_graph_file(&cgraph_file, walk->odb);
+       if (cgraph_file) {
+               git_commit_graph_entry e;
+
+               error = git_commit_graph_entry_find(&e, cgraph_file, &commit->oid, GIT_OID_RAWSZ);
+               if (error == 0 && git__is_uint16(e.parent_count)) {
+                       size_t i;
+                       commit->generation = (uint32_t)e.generation;
+                       commit->time = e.commit_time;
+                       commit->out_degree = (uint16_t)e.parent_count;
+                       commit->parents = alloc_parents(walk, commit, commit->out_degree);
+                       GIT_ERROR_CHECK_ALLOC(commit->parents);
+
+                       for (i = 0; i < commit->out_degree; ++i) {
+                               git_commit_graph_entry parent;
+                               error = git_commit_graph_entry_parent(&parent, cgraph_file, &e, i);
+                               if (error < 0)
+                                       return error;
+                               commit->parents[i] = git_revwalk__commit_lookup(walk, &parent.sha1);
+                       }
+                       commit->parsed = 1;
+                       return 0;
+               }
+       }
+
        if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0)
                return error;
 
index 6a65f8a766853d79f21698b9546e6cd3b932053e..aad39f3513b40f10d1589972c39eecb345f246d8 100644 (file)
@@ -26,6 +26,7 @@
 typedef struct git_commit_list_node {
        git_oid oid;
        int64_t time;
+       uint32_t generation;
        unsigned int seen:1,
                         uninteresting:1,
                         topo_delay:1,
@@ -45,6 +46,7 @@ typedef struct git_commit_list {
 } git_commit_list;
 
 git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk);
+int git_commit_list_generation_cmp(const void *a, const void *b);
 int git_commit_list_time_cmp(const void *a, const void *b);
 void git_commit_list_free(git_commit_list **list_p);
 git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p);
index 2b1a4a4569c7981bc348b294a729d341432e2cce..9bb1116b53149192793f6b64c8eab9a1a04c21ad 100644 (file)
@@ -19,6 +19,8 @@
 # define GIT_INLINE(type) static __inline type
 #elif defined(__GNUC__)
 # define GIT_INLINE(type) static __inline__ type
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define GIT_INLINE(type) static inline type
 #else
 # define GIT_INLINE(type) static type
 #endif
 # define __has_builtin(x) 0
 #endif
 
+/**
+ * Declare that a function's return value must be used.
+ *
+ * Used mostly to guard against potential silent bugs at runtime. This is
+ * recommended to be added to functions that:
+ *
+ * - Allocate / reallocate memory. This prevents memory leaks or errors where
+ *   buffers are expected to have grown to a certain size, but could not be
+ *   resized.
+ * - Acquire locks. When a lock cannot be acquired, that will almost certainly
+ *   cause a data race / undefined behavior.
+ */
+#if defined(__GNUC__)
+# define GIT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+# define GIT_WARN_UNUSED_RESULT
+#endif
+
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
@@ -63,7 +83,9 @@
 #      include <pthread.h>
 #      include <sched.h>
 # endif
-#define GIT_STDLIB_CALL
+
+#define GIT_LIBGIT2_CALL
+#define GIT_SYSTEM_CALL
 
 #ifdef GIT_USE_STAT_ATIMESPEC
 # define st_atim st_atimespec
 #include "git2/types.h"
 #include "git2/errors.h"
 #include "errors.h"
-#include "thread-utils.h"
+#include "thread.h"
 #include "integer.h"
 #include "assert_safe.h"
+#include "utf8.h"
 
 /*
  * Include the declarations for deprecated functions; this ensures
index 42f46e6cf12985aca4fdb13f8c943652fd55c677..3251cd51fdb46ec7ab1978807e6da2a60b25cae0 100644 (file)
@@ -10,7 +10,6 @@
 #include "git2/config.h"
 #include "git2/sys/config.h"
 
-#include "buf_text.h"
 #include "config_backend.h"
 #include "regexp.h"
 #include "sysdir.h"
@@ -108,7 +107,8 @@ int git_config_add_file_ondisk(
        struct stat st;
        int res;
 
-       assert(cfg && path);
+       GIT_ASSERT_ARG(cfg);
+       GIT_ASSERT_ARG(path);
 
        res = p_stat(path, &st);
        if (res < 0 && errno != ENOENT && errno != ENOTDIR) {
@@ -316,7 +316,8 @@ int git_config_add_backend(
        backend_internal *internal;
        int result;
 
-       assert(cfg && backend);
+       GIT_ASSERT_ARG(cfg);
+       GIT_ASSERT_ARG(backend);
 
        GIT_ERROR_CHECK_VERSION(backend, GIT_CONFIG_BACKEND_VERSION, "git_config_backend");
 
@@ -510,11 +511,12 @@ int git_config_backend_foreach_match(
        void *payload)
 {
        git_config_entry *entry;
-       git_config_iteratoriter;
+       git_config_iterator *iter;
        git_regexp regex;
        int error = 0;
 
-       assert(backend && cb);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(cb);
 
        if (regexp && git_regexp_compile(&regex, regexp, 0) < 0)
                return -1;
@@ -886,7 +888,8 @@ int git_config_get_string_buf(
        int ret;
        const char *str;
 
-       git_buf_sanitize(out);
+       if ((ret = git_buf_sanitize(out)) < 0)
+               return ret;
 
        ret  = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS);
        str = !ret ? (entry->value ? entry->value : "") : NULL;
@@ -1084,19 +1087,31 @@ void git_config_iterator_free(git_config_iterator *iter)
 
 int git_config_find_global(git_buf *path)
 {
-       git_buf_sanitize(path);
+       int error;
+
+       if ((error = git_buf_sanitize(path)) < 0)
+               return error;
+
        return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL);
 }
 
 int git_config_find_xdg(git_buf *path)
 {
-       git_buf_sanitize(path);
+       int error;
+
+       if ((error = git_buf_sanitize(path)) < 0)
+               return error;
+
        return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG);
 }
 
 int git_config_find_system(git_buf *path)
 {
-       git_buf_sanitize(path);
+       int error;
+
+       if ((error = git_buf_sanitize(path)) < 0)
+               return error;
+
        return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM);
 }
 
@@ -1104,7 +1119,9 @@ int git_config_find_programdata(git_buf *path)
 {
        int ret;
 
-       git_buf_sanitize(path);
+       if ((ret = git_buf_sanitize(path)) < 0)
+               return ret;
+
        ret = git_sysdir_find_programdata_file(path,
                                               GIT_CONFIG_FILENAME_PROGRAMDATA);
        if (ret != GIT_OK)
@@ -1182,7 +1199,7 @@ int git_config_lock(git_transaction **out, git_config *cfg)
        git_config_backend *backend;
        backend_internal *internal;
 
-       assert(cfg);
+       GIT_ASSERT_ARG(cfg);
 
        internal = git_vector_get(&cfg->backends, 0);
        if (!internal || !internal->backend) {
@@ -1202,7 +1219,7 @@ int git_config_unlock(git_config *cfg, int commit)
        git_config_backend *backend;
        backend_internal *internal;
 
-       assert(cfg);
+       GIT_ASSERT_ARG(cfg);
 
        internal = git_vector_get(&cfg->backends, 0);
        if (!internal || !internal->backend) {
@@ -1360,9 +1377,13 @@ fail_parse:
 
 int git_config_parse_path(git_buf *out, const char *value)
 {
-       assert(out && value);
+       int error;
 
-       git_buf_sanitize(out);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(value);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        if (value[0] == '~') {
                if (value[1] != '\0' && value[1] != '/') {
@@ -1405,7 +1426,8 @@ int git_config__normalize_name(const char *in, char **out)
 {
        char *name, *fdot, *ldot;
 
-       assert(in && out);
+       GIT_ASSERT_ARG(in);
+       GIT_ASSERT_ARG(out);
 
        name = git__strdup(in);
        GIT_ERROR_CHECK_ALLOC(name);
@@ -1474,7 +1496,7 @@ int git_config_rename_section(
        int error = 0;
        struct rename_data data;
 
-       git_buf_text_puts_escape_regex(&pattern, old_section_name);
+       git_buf_puts_escape_regex(&pattern, old_section_name);
 
        if ((error = git_buf_puts(&pattern, "\\..+")) < 0)
                goto cleanup;
index e4e071b540518b3b2bcabb23014a63f8431eb803..4bb91f52b9f254b8203ba524aef11993e83101bf 100644 (file)
@@ -86,6 +86,7 @@ static struct map_data _configmaps[] = {
        {"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT },
        {"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT },
        {"core.fsyncobjectfiles", NULL, 0, GIT_FSYNCOBJECTFILES_DEFAULT },
+       {"core.longpaths", NULL, 0, GIT_LONGPATHS_DEFAULT },
 };
 
 int git_config__configmap_lookup(int *out, git_config *config, git_configmap_item item)
@@ -111,17 +112,21 @@ int git_config__configmap_lookup(int *out, git_config *config, git_configmap_ite
 
 int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item)
 {
-       *out = repo->configmap_cache[(int)item];
+       intptr_t value = (intptr_t)git_atomic_load(repo->configmap_cache[(int)item]);
 
-       if (*out == GIT_CONFIGMAP_NOT_CACHED) {
-               int error;
+       *out = (int)value;
+
+       if (value == GIT_CONFIGMAP_NOT_CACHED) {
                git_config *config;
+               intptr_t oldval = value;
+               int error;
 
                if ((error = git_repository_config__weakptr(&config, repo)) < 0 ||
                        (error = git_config__configmap_lookup(out, config, item)) < 0)
                        return error;
 
-               repo->configmap_cache[(int)item] = *out;
+               value = *out;
+               git_atomic_compare_and_swap(&repo->configmap_cache[(int)item], (void *)oldval, (void *)value);
        }
 
        return 0;
index b1e0028369ac64af2d245c4132281dd172367b63..3588e6be6c4183da0ef1c33d56cccf6f90fad014 100644 (file)
@@ -164,23 +164,27 @@ out:
        return error;
 }
 
+static void config_file_clear_includes(config_file_backend *cfg)
+{
+       config_file *include;
+       uint32_t i;
+
+       git_array_foreach(cfg->file.includes, i, include)
+               config_file_clear(include);
+       git_array_clear(cfg->file.includes);
+}
+
 static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries)
 {
        config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
        git_config_entries *old = NULL;
-       config_file *include;
        int error;
-       uint32_t i;
 
        if (b->parent.readonly) {
                git_error_set(GIT_ERROR_CONFIG, "this backend is read-only");
                return -1;
        }
 
-       git_array_foreach(b->file.includes, i, include)
-               config_file_clear(include);
-       git_array_clear(b->file.includes);
-
        if ((error = git_mutex_lock(&b->values_mutex)) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to lock config backend");
                goto out;
@@ -202,6 +206,8 @@ static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *
        git_config_entries *entries = NULL;
        int error;
 
+       config_file_clear_includes(b);
+
        if ((error = git_config_entries_new(&entries)) < 0 ||
            (error = config_file_read_buffer(entries, b->repo, &b->file,
                                             b->level, 0, buf, buflen)) < 0 ||
@@ -229,6 +235,8 @@ static int config_file_refresh(git_config_backend *cfg)
        if (!modified)
                return 0;
 
+       config_file_clear_includes(b);
+
        if ((error = git_config_entries_new(&entries)) < 0 ||
            (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 ||
            (error = config_file_set_entries(cfg, entries)) < 0)
@@ -365,7 +373,7 @@ static int config_file_set_multivar(
        int result;
        char *key;
 
-       assert(regexp);
+       GIT_ASSERT_ARG(regexp);
 
        if ((result = git_config__normalize_name(name, &key)) < 0)
                return result;
@@ -531,7 +539,7 @@ static char *escape_value(const char *ptr)
        size_t len;
        const char *esc;
 
-       assert(ptr);
+       GIT_ASSERT_ARG_WITH_RETVAL(ptr, NULL);
 
        len = strlen(ptr);
        if (!len)
@@ -1096,7 +1104,7 @@ static int write_on_eof(
 /*
  * This is pretty much the parsing, except we write out anything we don't have
  */
-static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const charvalue)
+static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value)
 
 {
        char *orig_section = NULL, *section = NULL, *orig_name, *name, *ldot;
index ed2c87f6bcf5d74604c41f5e7ea2fdeac994e0eb..9f95e67d78c59df575c6aa8bf72fe4397b16ba9b 100644 (file)
@@ -7,8 +7,6 @@
 
 #include "config_parse.h"
 
-#include "buf_text.h"
-
 #include <ctype.h>
 
 const char *git_config_escapes = "ntb\"\\";
@@ -187,7 +185,7 @@ static int parse_section_header(git_config_parser *reader, char **section_out)
 
        /* Make sure we were given a section header */
        c = line[pos++];
-       assert(c == '[');
+       GIT_ASSERT(c == '[');
 
        c = line[pos++];
 
@@ -230,10 +228,10 @@ fail_parse:
 static int skip_bom(git_parse_ctx *parser)
 {
        git_buf buf = GIT_BUF_INIT_CONST(parser->content, parser->content_len);
-       git_bom_t bom;
-       int bom_offset = git_buf_text_detect_bom(&bom, &buf);
+       git_buf_bom_t bom;
+       int bom_offset = git_buf_detect_bom(&bom, &buf);
 
-       if (bom == GIT_BOM_UTF8)
+       if (bom == GIT_BUF_BOM_UTF8)
                git_parse_advance_chars(parser, bom_offset);
 
        /* TODO: reference implementation is pretty stupid with BoM */
@@ -351,7 +349,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_buf *value, i
                }
 
                /* If it was just a comment, pretend it didn't exist */
-               quote_count = strip_comments(line, !!in_quotes);
+               quote_count = strip_comments(line, in_quotes);
                if (line[0] == '\0')
                        goto next;
 
index 81b5216bc17cb08596e28d48fad4ff07739379dd..406f7140f211ce841b9ce18afa19b831c77ed83a 100644 (file)
@@ -15,7 +15,6 @@
 #include "futils.h"
 #include "hash.h"
 #include "filter.h"
-#include "buf_text.h"
 #include "repository.h"
 
 typedef enum {
@@ -219,7 +218,7 @@ static int crlf_apply_to_odb(
        if (ca->crlf_action == GIT_CRLF_BINARY || !git_buf_len(from))
                return GIT_PASSTHROUGH;
 
-       is_binary = git_buf_text_gather_stats(&stats, from, false);
+       is_binary = git_buf_gather_text_stats(&stats, from, false);
 
        /* Heuristics to see if we can skip the conversion.
         * Straight from Core Git.
@@ -247,7 +246,7 @@ static int crlf_apply_to_odb(
                return GIT_PASSTHROUGH;
 
        /* Actually drop the carriage returns */
-       return git_buf_text_crlf_to_lf(to, from);
+       return git_buf_crlf_to_lf(to, from);
 }
 
 static int crlf_apply_to_workdir(
@@ -262,7 +261,7 @@ static int crlf_apply_to_workdir(
        if (git_buf_len(from) == 0 || output_eol(ca) != GIT_EOL_CRLF)
                return GIT_PASSTHROUGH;
 
-       is_binary = git_buf_text_gather_stats(&stats, from, false);
+       is_binary = git_buf_gather_text_stats(&stats, from, false);
 
        /* If there are no LFs, or all LFs are part of a CRLF, nothing to do */
        if (stats.lf == 0 || stats.lf == stats.crlf)
@@ -281,7 +280,7 @@ static int crlf_apply_to_workdir(
                        return GIT_PASSTHROUGH;
        }
 
-       return git_buf_text_lf_to_crlf(to, from);
+       return git_buf_lf_to_crlf(to, from);
 }
 
 static int convert_attrs(
@@ -387,6 +386,17 @@ static int crlf_apply(
                return crlf_apply_to_odb(*payload, to, from, src);
 }
 
+static int crlf_stream(
+       git_writestream **out,
+       git_filter *self,
+       void **payload,
+       const git_filter_source *src,
+       git_writestream *next)
+{
+       return git_filter_buffered_stream_new(out,
+               self, crlf_apply, NULL, payload, src, next);
+}
+
 static void crlf_cleanup(
        git_filter *self,
        void       *payload)
@@ -406,7 +416,7 @@ git_filter *git_crlf_filter_new(void)
        f->f.initialize = NULL;
        f->f.shutdown = git_filter_free;
        f->f.check    = crlf_check;
-       f->f.apply    = crlf_apply;
+       f->f.stream   = crlf_stream;
        f->f.cleanup  = crlf_cleanup;
 
        return (git_filter *)f;
index 0e1b31aeed3f0cd2d4ff08200cb633a603229309..2297ee66cf34b0a912ed270c6cf7f8ab0c3c6407 100644 (file)
@@ -204,7 +204,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
        if (month > 0 && month < 13 && day > 0 && day < 32) {
                struct tm check = *tm;
                struct tm *r = (now_tm ? &check : tm);
-               time_t specified;
+               git_time_t specified;
 
                r->tm_mon = month - 1;
                r->tm_mday = day;
@@ -722,7 +722,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
        while (tl->type) {
                size_t len = strlen(tl->type);
                if (match_string(date, tl->type) >= len-1) {
-                       update_tm(tm, now, tl->length * *num);
+                       update_tm(tm, now, tl->length * (unsigned long)*num);
                        *num = 0;
                        *touched = 1;
                        return end;
@@ -881,7 +881,8 @@ int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date)
        struct tm gmt;
        time_t t;
 
-       assert(out && date);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(date);
 
        t = (time_t) (date->time + date->offset * 60);
 
index 1ff7752c7d8210099e858e2b2303508a1e54f8b2..2d2c5fa85bb11fac31ca083a1db41a36168fd9bf 100644 (file)
@@ -256,7 +256,7 @@ void git_delta_index_free(git_delta_index *index)
 
 size_t git_delta_index_size(git_delta_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        return index->memsize;
 }
index 8beffdebaa68a89f5503bf5b1f551c2a6ec3d445..103d0da5c8d212f39c831e46c11e9d608c54de28 100644 (file)
@@ -391,7 +391,7 @@ static int show_suffix(
        git_buf *buf,
        int depth,
        git_repository *repo,
-       const git_oidid,
+       const git_oid *id,
        unsigned int abbrev_size)
 {
        int error, size = 0;
@@ -655,7 +655,8 @@ int git_describe_commit(
        int error = -1;
        git_describe_options normalized;
 
-       assert(committish);
+       GIT_ASSERT_ARG(result);
+       GIT_ASSERT_ARG(committish);
 
        data.result = git__calloc(1, sizeof(git_describe_result));
        GIT_ERROR_CHECK_ALLOC(data.result);
@@ -775,12 +776,14 @@ int git_describe_format(git_buf *out, const git_describe_result *result, const g
        struct commit_name *name;
        git_describe_format_options opts;
 
-       assert(out && result);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(result);
 
        GIT_ERROR_CHECK_VERSION(given, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, "git_describe_format_options");
        normalize_format_options(&opts, given);
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
 
        if (opts.always_use_long_format && opts.abbreviated_size == 0) {
index 3e52e3f18df46fce5e1b82b514a9b407357d225f..30b9f647a45a37fede8ef611a6132aad26d25050 100644 (file)
@@ -7,11 +7,15 @@
 
 #include "diff.h"
 
-#include "git2/version.h"
-#include "diff_generate.h"
+#include "common.h"
 #include "patch.h"
+#include "email.h"
 #include "commit.h"
 #include "index.h"
+#include "diff_generate.h"
+
+#include "git2/version.h"
+#include "git2/email.h"
 
 struct patch_id_args {
        git_hash_ctx ctx;
@@ -77,7 +81,7 @@ void git_diff_addref(git_diff *diff)
 
 size_t git_diff_num_deltas(const git_diff *diff)
 {
-       assert(diff);
+       GIT_ASSERT_ARG(diff);
        return diff->deltas.length;
 }
 
@@ -86,7 +90,7 @@ size_t git_diff_num_deltas_of_type(const git_diff *diff, git_delta_t type)
        size_t i, count = 0;
        const git_diff_delta *delta;
 
-       assert(diff);
+       GIT_ASSERT_ARG(diff);
 
        git_vector_foreach(&diff->deltas, i, delta) {
                count += (delta->status == type);
@@ -97,7 +101,7 @@ size_t git_diff_num_deltas_of_type(const git_diff *diff, git_delta_t type)
 
 const git_diff_delta *git_diff_get_delta(const git_diff *diff, size_t idx)
 {
-       assert(diff);
+       GIT_ASSERT_ARG_WITH_RETVAL(diff, NULL);
        return git_vector_get(&diff->deltas, idx);
 }
 
@@ -108,7 +112,7 @@ int git_diff_is_sorted_icase(const git_diff *diff)
 
 int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff)
 {
-       assert(out);
+       GIT_ASSERT_ARG(out);
        GIT_ERROR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
        out->stat_calls = diff->perf.stat_calls;
        out->oid_calculations = diff->perf.oid_calculations;
@@ -127,7 +131,7 @@ int git_diff_foreach(
        git_diff_delta *delta;
        size_t idx;
 
-       assert(diff);
+       GIT_ASSERT_ARG(diff);
 
        git_vector_foreach(&diff->deltas, idx, delta) {
                git_patch *patch;
@@ -150,164 +154,31 @@ int git_diff_foreach(
        return error;
 }
 
-static int diff_format_email_append_header_tobuf(
-       git_buf *out,
-       const git_oid *id,
-       const git_signature *author,
-       const char *summary,
-       const char *body,
-       size_t patch_no,
-       size_t total_patches,
-       bool exclude_patchno_marker)
-{
-       char idstr[GIT_OID_HEXSZ + 1];
-       char date_str[GIT_DATE_RFC2822_SZ];
-       int error = 0;
-
-       git_oid_fmt(idstr, id);
-       idstr[GIT_OID_HEXSZ] = '\0';
-
-       if ((error = git__date_rfc2822_fmt(date_str, sizeof(date_str),
-               &author->when)) < 0)
-               return error;
-
-       error = git_buf_printf(out,
-                               "From %s Mon Sep 17 00:00:00 2001\n" \
-                               "From: %s <%s>\n" \
-                               "Date: %s\n" \
-                               "Subject: ",
-                               idstr,
-                               author->name, author->email,
-                               date_str);
-
-       if (error < 0)
-               return error;
-
-       if (!exclude_patchno_marker) {
-               if (total_patches == 1) {
-                       error = git_buf_puts(out, "[PATCH] ");
-               } else {
-                       error = git_buf_printf(out, "[PATCH %"PRIuZ"/%"PRIuZ"] ",
-                               patch_no, total_patches);
-               }
-
-               if (error < 0)
-                       return error;
-       }
-
-       error = git_buf_printf(out, "%s\n\n", summary);
-
-       if (body) {
-               git_buf_puts(out, body);
-
-               if (out->ptr[out->size - 1] != '\n')
-                       git_buf_putc(out, '\n');
-       }
-
-       return error;
-}
-
-static int diff_format_email_append_patches_tobuf(
-       git_buf *out,
-       git_diff *diff)
-{
-       size_t i, deltas;
-       int error = 0;
-
-       deltas = git_diff_num_deltas(diff);
-
-       for (i = 0; i < deltas; ++i) {
-               git_patch *patch = NULL;
-
-               if ((error = git_patch_from_diff(&patch, diff, i)) >= 0)
-                       error = git_patch_to_buf(out, patch);
-
-               git_patch_free(patch);
-
-               if (error < 0)
-                       break;
-       }
-
-       return error;
-}
+#ifndef GIT_DEPRECATE_HARD
 
 int git_diff_format_email(
        git_buf *out,
        git_diff *diff,
        const git_diff_format_email_options *opts)
 {
-       git_diff_stats *stats = NULL;
-       char *summary = NULL, *loc = NULL;
-       bool ignore_marker;
-       unsigned int format_flags = 0;
-       size_t allocsize;
+       git_email_create_options email_create_opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
        int error;
 
-       assert(out && diff && opts);
-       assert(opts->summary && opts->id && opts->author);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diff);
+       GIT_ASSERT_ARG(opts && opts->summary && opts->id && opts->author);
 
        GIT_ERROR_CHECK_VERSION(opts,
                GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION,
                "git_format_email_options");
 
-       ignore_marker = (opts->flags &
-               GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) != 0;
-
-       if (!ignore_marker) {
-               if (opts->patch_no > opts->total_patches) {
-                       git_error_set(GIT_ERROR_INVALID,
-                               "patch %"PRIuZ" out of range. max %"PRIuZ,
-                               opts->patch_no, opts->total_patches);
-                       return -1;
-               }
+       if ((opts->flags & GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) != 0)
+               email_create_opts.subject_prefix = "";
 
-               if (opts->patch_no == 0) {
-                       git_error_set(GIT_ERROR_INVALID,
-                               "invalid patch no %"PRIuZ". should be >0", opts->patch_no);
-                       return -1;
-               }
-       }
 
-       /* the summary we receive may not be clean.
-        * it could potentially contain new line characters
-        * or not be set, sanitize, */
-       if ((loc = strpbrk(opts->summary, "\r\n")) != NULL) {
-               size_t offset = 0;
-
-               if ((offset = (loc - opts->summary)) == 0) {
-                       git_error_set(GIT_ERROR_INVALID, "summary is empty");
-                       error = -1;
-                       goto on_error;
-               }
-
-               GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, offset, 1);
-               summary = git__calloc(allocsize, sizeof(char));
-               GIT_ERROR_CHECK_ALLOC(summary);
-
-               strncpy(summary, opts->summary, offset);
-       }
-
-       error = diff_format_email_append_header_tobuf(out,
-               opts->id, opts->author, summary == NULL ? opts->summary : summary,
-               opts->body, opts->patch_no, opts->total_patches, ignore_marker);
-
-       if (error < 0)
-               goto on_error;
-
-       format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY;
-
-       if ((error = git_buf_puts(out, "---\n")) < 0 ||
-               (error = git_diff_get_stats(&stats, diff)) < 0 ||
-               (error = git_diff_stats_to_buf(out, stats, format_flags, 0)) < 0 ||
-               (error = git_buf_putc(out, '\n')) < 0 ||
-               (error = diff_format_email_append_patches_tobuf(out, diff)) < 0)
-                       goto on_error;
-
-       error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
-
-on_error:
-       git__free(summary);
-       git_diff_stats_free(stats);
+       error = git_email__append_from_diff(out, diff, opts->patch_no,
+               opts->total_patches, opts->id, opts->summary, opts->body,
+               opts->author, &email_create_opts);
 
        return error;
 }
@@ -322,58 +193,43 @@ int git_diff_commit_as_email(
        const git_diff_options *diff_opts)
 {
        git_diff *diff = NULL;
-       git_diff_format_email_options opts =
-               GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+       const git_oid *commit_id;
+       const char *summary, *body;
+       const git_signature *author;
        int error;
 
-       assert (out && repo && commit);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(commit);
+
+       commit_id = git_commit_id(commit);
+       summary = git_commit_summary(commit);
+       body = git_commit_body(commit);
+       author = git_commit_author(commit);
 
-       opts.flags = flags;
-       opts.patch_no = patch_no;
-       opts.total_patches = total_patches;
-       opts.id = git_commit_id(commit);
-       opts.summary = git_commit_summary(commit);
-       opts.body = git_commit_body(commit);
-       opts.author = git_commit_author(commit);
+       if ((flags & GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) != 0)
+               opts.subject_prefix = "";
 
        if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0)
                return error;
 
-       error = git_diff_format_email(out, diff, &opts);
+       error = git_email_create_from_diff(out, diff, patch_no, total_patches, commit_id, summary, body, author, &opts);
 
        git_diff_free(diff);
        return error;
 }
 
-int git_diff_options_init(git_diff_options *opts, unsigned int version)
-{
-       GIT_INIT_STRUCTURE_FROM_TEMPLATE(
-               opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT);
-       return 0;
-}
-
-#ifndef GIT_DEPRECATE_HARD
 int git_diff_init_options(git_diff_options *opts, unsigned int version)
 {
        return git_diff_options_init(opts, version);
 }
-#endif
 
-int git_diff_find_options_init(
-       git_diff_find_options *opts, unsigned int version)
-{
-       GIT_INIT_STRUCTURE_FROM_TEMPLATE(
-               opts, version, git_diff_find_options, GIT_DIFF_FIND_OPTIONS_INIT);
-       return 0;
-}
-
-#ifndef GIT_DEPRECATE_HARD
 int git_diff_find_init_options(
        git_diff_find_options *opts, unsigned int version)
 {
        return git_diff_find_options_init(opts, version);
 }
-#endif
 
 int git_diff_format_email_options_init(
        git_diff_format_email_options *opts, unsigned int version)
@@ -384,14 +240,29 @@ int git_diff_format_email_options_init(
        return 0;
 }
 
-#ifndef GIT_DEPRECATE_HARD
 int git_diff_format_email_init_options(
        git_diff_format_email_options *opts, unsigned int version)
 {
        return git_diff_format_email_options_init(opts, version);
 }
+
 #endif
 
+int git_diff_options_init(git_diff_options *opts, unsigned int version)
+{
+       GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+               opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT);
+       return 0;
+}
+
+int git_diff_find_options_init(
+       git_diff_find_options *opts, unsigned int version)
+{
+       GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+               opts, version, git_diff_find_options, GIT_DIFF_FIND_OPTIONS_INIT);
+       return 0;
+}
+
 static int flush_hunk(git_oid *result, git_hash_ctx *ctx)
 {
        git_oid hash;
index 831d3262dce930a45a256ea1fd1067315ecdef8a..a3892d35eeaa68e53a62819c728f323410a90c27 100644 (file)
@@ -13,7 +13,6 @@
 #include "diff.h"
 #include "strmap.h"
 #include "map.h"
-#include "buf_text.h"
 #include "config.h"
 #include "regexp.h"
 #include "repository.h"
@@ -142,18 +141,23 @@ static int diff_driver_funcname(const git_config_entry *entry, void *payload)
 static git_diff_driver_registry *git_repository_driver_registry(
        git_repository *repo)
 {
-       if (!repo->diff_drivers) {
-               git_diff_driver_registry *reg = git_diff_driver_registry_new();
-               reg = git__compare_and_swap(&repo->diff_drivers, NULL, reg);
+       git_diff_driver_registry *reg = git_atomic_load(repo->diff_drivers), *newreg;
+       if (reg)
+               return reg;
 
-               if (reg != NULL) /* if we race, free losing allocation */
-                       git_diff_driver_registry_free(reg);
-       }
-
-       if (!repo->diff_drivers)
+       newreg = git_diff_driver_registry_new();
+       if (!newreg) {
                git_error_set(GIT_ERROR_REPOSITORY, "unable to create diff driver registry");
-
-       return repo->diff_drivers;
+               return newreg;
+       }
+       reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, newreg);
+       if (!reg) {
+               reg = newreg;
+       } else {
+               /* if we race, free losing allocation */
+               git_diff_driver_registry_free(newreg);
+       }
+       return reg;
 }
 
 static int diff_driver_alloc(
@@ -358,7 +362,7 @@ int git_diff_driver_lookup(
        int error = 0;
        const char *values[1], *attrs[] = { "diff" };
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
        *out = NULL;
 
        if (!repo || !path || !strlen(path))
@@ -390,13 +394,13 @@ int git_diff_driver_lookup(
 
 void git_diff_driver_free(git_diff_driver *driver)
 {
-       size_t i;
+       git_diff_driver_pattern *pat;
 
        if (!driver)
                return;
 
-       for (i = 0; i < git_array_size(driver->fn_patterns); ++i)
-               git_regexp_dispose(& git_array_get(driver->fn_patterns, i)->re);
+       while ((pat = git_array_pop(driver->fn_patterns)) != NULL)
+               git_regexp_dispose(&pat->re);
        git_array_clear(driver->fn_patterns);
 
        git_regexp_dispose(&driver->word_pattern);
@@ -428,8 +432,8 @@ int git_diff_driver_content_is_binary(
         * let's just use the simple NUL-byte detection that core git uses.
         */
 
-       /* previously was: if (git_buf_text_is_binary(&search)) */
-       if (git_buf_text_contains_nul(&search))
+       /* previously was: if (git_buf_is_binary(&search)) */
+       if (git_buf_contains_nul(&search))
                return 1;
 
        return 0;
index 015e0706b4ca3e0ac4876f71c397d791c402775e..eeaf4a5a274fc6873073eddba40e1ac90ca41084 100644 (file)
@@ -362,10 +362,7 @@ static int diff_file_content_load_workdir_file(
        if (!(error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size))) {
                git_buf out = GIT_BUF_INIT;
 
-               error = git_filter_list_apply_to_data(&out, fl, &raw);
-
-               if (out.ptr != raw.ptr)
-                       git_buf_dispose(&raw);
+               error = git_filter_list__convert_buf(&out, fl, &raw);
 
                if (!error) {
                        fc->map.len  = out.size;
@@ -394,8 +391,7 @@ static int diff_file_content_load_workdir(
        if (fc->file->mode == GIT_FILEMODE_TREE)
                return 0;
 
-       if (git_buf_joinpath(
-                       &path, git_repository_workdir(fc->repo), fc->file->path) < 0)
+       if (git_repository_workdir_path(&path, fc->repo, fc->file->path) < 0)
                return -1;
 
        if (S_ISLNK(fc->file->mode))
index e7bfd6223fad98f73512dd9fab11fda9a65122b1..aba9e52ba7fa94470fa38073a69eabc0bd91644f 100644 (file)
@@ -128,7 +128,7 @@ static int diff_delta__from_one(
        git_diff_delta *delta;
        const char *matched_pathspec;
 
-       assert((oitem != NULL) ^ (nitem != NULL));
+       GIT_ASSERT_ARG((oitem != NULL) ^ (nitem != NULL));
 
        if (oitem) {
                entry = oitem;
@@ -160,7 +160,7 @@ static int diff_delta__from_one(
        GIT_ERROR_CHECK_ALLOC(delta);
 
        /* This fn is just for single-sided diffs */
-       assert(status != GIT_DELTA_MODIFIED);
+       GIT_ASSERT(status != GIT_DELTA_MODIFIED);
        delta->nfiles = 1;
 
        if (has_old) {
@@ -408,7 +408,9 @@ static git_diff_generated *diff_generated_alloc(
        git_diff_generated *diff;
        git_diff_options dflt = GIT_DIFF_OPTIONS_INIT;
 
-       assert(repo && old_iter && new_iter);
+       GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(old_iter, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(new_iter, NULL);
 
        if ((diff = git__calloc(1, sizeof(git_diff_generated))) == NULL)
                return NULL;
@@ -589,13 +591,12 @@ int git_diff__oid_for_entry(
        git_filter_list *fl = NULL;
        int error = 0;
 
-       assert(d->type == GIT_DIFF_TYPE_GENERATED);
+       GIT_ASSERT(d->type == GIT_DIFF_TYPE_GENERATED);
        diff = (git_diff_generated *)d;
 
        memset(out, 0, sizeof(*out));
 
-       if (git_buf_joinpath(&full_path,
-               git_repository_workdir(diff->base.repo), entry.path) < 0)
+       if (git_repository_workdir_path(&full_path, diff->base.repo, entry.path) < 0)
                return -1;
 
        if (!mode) {
@@ -678,6 +679,8 @@ typedef struct {
        git_iterator *new_iter;
        const git_index_entry *oitem;
        const git_index_entry *nitem;
+       git_strmap *submodule_cache;
+       bool submodule_cache_initialized;
 } diff_in_progress;
 
 #define MODE_BITS_MASK 0000777
@@ -692,6 +695,7 @@ static int maybe_modified_submodule(
        git_submodule *sub;
        unsigned int sm_status = 0;
        git_submodule_ignore_t ign = diff->base.opts.ignore_submodules;
+       git_strmap *submodule_cache = NULL;
 
        *status = GIT_DELTA_UNMODIFIED;
 
@@ -699,8 +703,23 @@ static int maybe_modified_submodule(
                ign == GIT_SUBMODULE_IGNORE_ALL)
                return 0;
 
-       if ((error = git_submodule_lookup(
-                       &sub, diff->base.repo, info->nitem->path)) < 0) {
+       if (diff->base.repo->submodule_cache != NULL) {
+               submodule_cache = diff->base.repo->submodule_cache;
+       } else {
+               if (!info->submodule_cache_initialized) {
+                       info->submodule_cache_initialized = true;
+                       /*
+                        * Try to cache the submodule information to avoid having to parse it for
+                        * every submodule. It is okay if it fails, the cache will still be NULL
+                        * and the submodules will be attempted to be looked up individually.
+                        */
+                       git_submodule_cache_init(&info->submodule_cache, diff->base.repo);
+               }
+               submodule_cache = info->submodule_cache;
+       }
+
+       if ((error = git_submodule__lookup_with_cache(
+                       &sub, diff->base.repo, info->nitem->path, submodule_cache)) < 0) {
 
                /* GIT_EEXISTS means dir with .git in it was found - ignore it */
                if (error == GIT_EEXISTS) {
@@ -1190,7 +1209,7 @@ int git_diff__from_iterators(
        const git_diff_options *opts)
 {
        git_diff_generated *diff;
-       diff_in_progress info;
+       diff_in_progress info = {0};
        int error = 0;
 
        *out = NULL;
@@ -1204,8 +1223,9 @@ int git_diff__from_iterators(
 
        /* make iterators have matching icase behavior */
        if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE)) {
-               git_iterator_set_ignore_case(old_iter, true);
-               git_iterator_set_ignore_case(new_iter, true);
+               if ((error = git_iterator_set_ignore_case(old_iter, true)) < 0 ||
+                   (error = git_iterator_set_ignore_case(new_iter, true)) < 0)
+                       goto cleanup;
        }
 
        /* finish initialization */
@@ -1257,6 +1277,8 @@ cleanup:
                *out = &diff->base;
        else
                git_diff_free(&diff->base);
+       if (info.submodule_cache)
+               git_submodule_cache_free(info.submodule_cache);
 
        return error;
 }
@@ -1302,7 +1324,8 @@ int git_diff_tree_to_tree(
        char *prefix = NULL;
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -1358,7 +1381,8 @@ int git_diff_tree_to_index(
        bool index_ignore_case = false;
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -1401,7 +1425,8 @@ int git_diff_index_to_workdir(
        char *prefix = NULL;
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -1444,7 +1469,8 @@ int git_diff_tree_to_workdir(
        git_index *index;
        int error;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -1477,7 +1503,8 @@ int git_diff_tree_to_workdir_with_index(
        git_index *index = NULL;
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -1513,7 +1540,9 @@ int git_diff_index_to_index(
        char *prefix = NULL;
        int error;
 
-       assert(out && old_index && new_index);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(old_index);
+       GIT_ASSERT_ARG(new_index);
 
        *out = NULL;
 
index 9ce04d70e357f1ea2ed71adc78c3acd64bef1440..062e267b00c7cece47de3efed67cf45396422ce4 100644 (file)
@@ -95,7 +95,7 @@ static int diff_print_info_init_frompatch(
        git_diff_line_cb cb,
        void *payload)
 {
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
 
        memset(pi, 0, sizeof(diff_print_info));
 
@@ -764,8 +764,14 @@ int git_diff_print_callback__to_file_handle(
 /* print a git_diff to a git_buf */
 int git_diff_to_buf(git_buf *out, git_diff *diff, git_diff_format_t format)
 {
-       assert(out && diff);
-       git_buf_sanitize(out);
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diff);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
+
        return git_diff_print(diff, format, git_diff_print_callback__to_buf, out);
 }
 
@@ -779,7 +785,8 @@ int git_patch_print(
        diff_print_info pi;
        int error;
 
-       assert(patch && print_cb);
+       GIT_ASSERT_ARG(patch);
+       GIT_ASSERT_ARG(print_cb);
 
        if ((error = diff_print_info_init_frompatch(&pi, &temp, patch,
                                                    GIT_DIFF_FORMAT_PATCH, print_cb, payload)) < 0)
@@ -799,7 +806,13 @@ out:
 /* print a git_patch to a git_buf */
 int git_patch_to_buf(git_buf *out, git_patch *patch)
 {
-       assert(out && patch);
-       git_buf_sanitize(out);
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(patch);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
+
        return git_patch_print(patch, git_diff_print_callback__to_buf, out);
 }
index f5fda7925318fbcb7fcb01ef173df9455f0796a9..41a25bf8acaaf0574a153878a554b7167882d1ac 100644 (file)
@@ -183,7 +183,8 @@ int git_diff_get_stats(
        git_diff_stats *stats = NULL;
        int error = 0;
 
-       assert(out && diff);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diff);
 
        stats = git__calloc(1, sizeof(git_diff_stats));
        GIT_ERROR_CHECK_ALLOC(stats);
@@ -251,7 +252,7 @@ int git_diff_get_stats(
 size_t git_diff_stats_files_changed(
        const git_diff_stats *stats)
 {
-       assert(stats);
+       GIT_ASSERT_ARG(stats);
 
        return stats->files_changed;
 }
@@ -259,7 +260,7 @@ size_t git_diff_stats_files_changed(
 size_t git_diff_stats_insertions(
        const git_diff_stats *stats)
 {
-       assert(stats);
+       GIT_ASSERT_ARG(stats);
 
        return stats->insertions;
 }
@@ -267,7 +268,7 @@ size_t git_diff_stats_insertions(
 size_t git_diff_stats_deletions(
        const git_diff_stats *stats)
 {
-       assert(stats);
+       GIT_ASSERT_ARG(stats);
 
        return stats->deletions;
 }
@@ -282,7 +283,8 @@ int git_diff_stats_to_buf(
        size_t i;
        const git_diff_delta *delta;
 
-       assert(out && stats);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(stats);
 
        if (format & GIT_DIFF_STATS_NUMBER) {
                for (i = 0; i < stats->files_changed; ++i) {
index 7de88bd0d81894a297546ed535fda723e29a5b24..908175d34128ce3aea5778eaab5ea559f9fc78c1 100644 (file)
@@ -87,7 +87,7 @@ git_diff_delta *git_diff__merge_like_cgit(
                a->status == GIT_DELTA_UNREADABLE)
                return dup;
 
-       assert(b->status != GIT_DELTA_UNMODIFIED);
+       GIT_ASSERT_WITH_RETVAL(b->status != GIT_DELTA_UNMODIFIED, NULL);
 
        /* A cgit exception is that the diff of a file that is only in the
         * index (i.e. not in HEAD nor workdir) is given as empty.
@@ -121,7 +121,8 @@ int git_diff__merge(
        bool ignore_case, reversed;
        unsigned int i, j;
 
-       assert(onto && from);
+       GIT_ASSERT_ARG(onto);
+       GIT_ASSERT_ARG(from);
 
        if (!from->deltas.length)
                return 0;
@@ -475,8 +476,8 @@ static int similarity_sig(
        git_diff_file *file = info->file;
 
        if (info->src == GIT_ITERATOR_WORKDIR) {
-               if ((error = git_buf_joinpath(
-                       &info->data, git_repository_workdir(info->repo), file->path)) < 0)
+               if ((error = git_repository_workdir_path(
+                       &info->data, info->repo, file->path)) < 0)
                        return error;
 
                /* if path is not a regular file, just skip this item */
@@ -815,7 +816,7 @@ int git_diff_find_similar(
        diff_find_match *best_match;
        git_diff_file swap;
 
-       assert(diff);
+       GIT_ASSERT_ARG(diff);
 
        if ((error = normalize_find_opts(diff, &opts, given_opts)) < 0)
                return error;
@@ -978,7 +979,7 @@ find_best_matches:
                                src->flags |= GIT_DIFF_FLAG__TO_DELETE;
                                num_rewrites++;
                        } else {
-                               assert(delta_is_split(tgt));
+                               GIT_ASSERT(delta_is_split(tgt));
 
                                if (best_match->similarity < opts.rename_from_rewrite_threshold)
                                        continue;
@@ -988,7 +989,7 @@ find_best_matches:
                                delta_make_rename(tgt, src, best_match->similarity);
                                num_rewrites--;
 
-                               assert(src->status == GIT_DELTA_DELETED);
+                               GIT_ASSERT(src->status == GIT_DELTA_DELETED);
                                memcpy(&src->old_file, &swap, sizeof(src->old_file));
                                memset(&src->new_file, 0, sizeof(src->new_file));
                                src->new_file.path = src->old_file.path;
@@ -1024,7 +1025,7 @@ find_best_matches:
 
                                num_updates++;
                        } else {
-                               assert(delta_is_split(src));
+                               GIT_ASSERT(delta_is_split(src));
 
                                if (best_match->similarity < opts.rename_from_rewrite_threshold)
                                        continue;
@@ -1038,7 +1039,7 @@ find_best_matches:
                                memcpy(&src->old_file, &swap, sizeof(src->old_file));
 
                                /* if we've just swapped the new element into the correct
-                                * place, clear the SPLIT flag
+                                * place, clear the SPLIT and RENAME_TARGET flags
                                 */
                                if (tgt2src[s].idx == t &&
                                        tgt2src[s].similarity >
@@ -1046,7 +1047,7 @@ find_best_matches:
                                        src->status     = GIT_DELTA_RENAMED;
                                        src->similarity = tgt2src[s].similarity;
                                        tgt2src[s].similarity = 0;
-                                       src->flags &= ~GIT_DIFF_FLAG__TO_SPLIT;
+                                       src->flags &= ~(GIT_DIFF_FLAG__TO_SPLIT | GIT_DIFF_FLAG__IS_RENAME_TARGET);
                                        num_rewrites--;
                                }
                                /* otherwise, if we just overwrote a source, update mapping */
index c4668fa2fdca4d6451166d968a0652d9ff64e8cd..278e2be36e94c63a55875fb442cc5f4aae1a3baa 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "diff_xdiff.h"
-#include "util.h"
 
 #include "git2/errors.h"
 #include "diff.h"
@@ -128,7 +127,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
                        info->hunk.header_len = sizeof(info->hunk.header) - 1;
 
                /* Sanitize the hunk header in case there is invalid Unicode */
-               buffer_len = git__utf8_valid_buf_length((const uint8_t *) bufs[0].ptr, info->hunk.header_len);
+               buffer_len = git_utf8_valid_buf_length(bufs[0].ptr, info->hunk.header_len);
                /* Sanitizing the hunk header may delete the newline, so add it back again if there is room */
                if (buffer_len < info->hunk.header_len) {
                        bufs[0].ptr[buffer_len] = '\n';
@@ -259,5 +258,8 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
        if (flags & GIT_DIFF_MINIMAL)
                xo->params.flags |= XDF_NEED_MINIMAL;
 
+       if (flags & GIT_DIFF_IGNORE_BLANK_LINES)
+               xo->params.flags |= XDF_IGNORE_BLANK_LINES;
+
        xo->callback.outf = git_xdiff_cb;
 }
index aca80b131069f7a796256f8abfea58a39471ddd3..9b303e9dc4516925d17763cc3f07966f0bdd10a8 100644 (file)
@@ -16,7 +16,7 @@
 /* xdiff cannot cope with large files.  these files should not be passed to
  * xdiff.  callers should treat these large files as binary.
  */
-#define GIT_XDIFF_MAX_SIZE (1024LL * 1024 * 1023)
+#define GIT_XDIFF_MAX_SIZE (INT64_C(1024) * 1024 * 1023)
 
 /* A git_xdiff_output is a git_patch_generate_output with extra fields
  * necessary to use libxdiff.  Calling git_xdiff_init() will set the diff_cb
diff --git a/src/email.c b/src/email.c
new file mode 100644 (file)
index 0000000..df63b6e
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "email.h"
+
+#include "buffer.h"
+#include "common.h"
+#include "diff_generate.h"
+
+#include "git2/email.h"
+#include "git2/patch.h"
+#include "git2/version.h"
+
+/*
+ * Git uses a "magic" timestamp to indicate that an email message
+ * is from `git format-patch` (or our equivalent).
+ */
+#define EMAIL_TIMESTAMP "Mon Sep 17 00:00:00 2001"
+
+GIT_INLINE(int) include_prefix(
+       size_t patch_count,
+       git_email_create_options *opts)
+{
+       return ((!opts->subject_prefix || *opts->subject_prefix) ||
+               (opts->flags & GIT_EMAIL_CREATE_ALWAYS_NUMBER) != 0 ||
+               opts->reroll_number ||
+               (patch_count > 1 && !(opts->flags & GIT_EMAIL_CREATE_OMIT_NUMBERS)));
+}
+
+static int append_prefix(
+       git_buf *out,
+       size_t patch_idx,
+       size_t patch_count,
+       git_email_create_options *opts)
+{
+       const char *subject_prefix = opts->subject_prefix ?
+               opts->subject_prefix : "PATCH";
+
+       git_buf_putc(out, '[');
+
+       if (*subject_prefix)
+               git_buf_puts(out, subject_prefix);
+
+       if (opts->reroll_number) {
+               if (*subject_prefix)
+                       git_buf_putc(out, ' ');
+
+               git_buf_printf(out, "v%" PRIuZ, opts->reroll_number);
+       }
+
+       if ((opts->flags & GIT_EMAIL_CREATE_ALWAYS_NUMBER) != 0 ||
+           (patch_count > 1 && !(opts->flags & GIT_EMAIL_CREATE_OMIT_NUMBERS))) {
+               size_t start_number = opts->start_number ?
+                       opts->start_number : 1;
+
+               if (*subject_prefix || opts->reroll_number)
+                       git_buf_putc(out, ' ');
+
+               git_buf_printf(out, "%" PRIuZ "/%" PRIuZ,
+                              patch_idx + (start_number - 1),
+                              patch_count + (start_number - 1));
+       }
+
+       git_buf_puts(out, "]");
+
+       return git_buf_oom(out) ? -1 : 0;
+}
+
+static int append_subject(
+       git_buf *out,
+       size_t patch_idx,
+       size_t patch_count,
+       const char *summary,
+       git_email_create_options *opts)
+{
+       bool prefix = include_prefix(patch_count, opts);
+       size_t summary_len = summary ? strlen(summary) : 0;
+       int error;
+
+       if (summary_len) {
+               const char *nl = strchr(summary, '\n');
+
+               if (nl)
+                       summary_len = (nl - summary);
+       }
+
+       if ((error = git_buf_puts(out, "Subject: ")) < 0)
+               return error;
+
+       if (prefix &&
+           (error = append_prefix(out, patch_idx, patch_count, opts)) < 0)
+               return error;
+
+       if (prefix && summary_len && (error = git_buf_putc(out, ' ')) < 0)
+               return error;
+
+       if (summary_len &&
+           (error = git_buf_put(out, summary, summary_len)) < 0)
+               return error;
+
+       return git_buf_putc(out, '\n');
+}
+
+static int append_header(
+       git_buf *out,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const git_signature *author,
+       git_email_create_options *opts)
+{
+       char id[GIT_OID_HEXSZ];
+       char date[GIT_DATE_RFC2822_SZ];
+       int error;
+
+       if ((error = git_oid_fmt(id, commit_id)) < 0 ||
+           (error = git_buf_printf(out, "From %.*s %s\n", GIT_OID_HEXSZ, id, EMAIL_TIMESTAMP)) < 0 ||
+           (error = git_buf_printf(out, "From: %s <%s>\n", author->name, author->email)) < 0 ||
+           (error = git__date_rfc2822_fmt(date, sizeof(date), &author->when)) < 0 ||
+           (error = git_buf_printf(out, "Date: %s\n", date)) < 0 ||
+           (error = append_subject(out, patch_idx, patch_count, summary, opts)) < 0)
+               return error;
+
+       if ((error = git_buf_putc(out, '\n')) < 0)
+               return error;
+
+       return 0;
+}
+
+static int append_body(git_buf *out, const char *body)
+{
+       size_t body_len;
+       int error;
+
+       if (!body)
+               return 0;
+
+       body_len = strlen(body);
+
+       if ((error = git_buf_puts(out, body)) < 0)
+               return error;
+
+       if (body_len && body[body_len - 1] != '\n')
+               error = git_buf_putc(out, '\n');
+
+       return error;
+}
+
+static int append_diffstat(git_buf *out, git_diff *diff)
+{
+       git_diff_stats *stats = NULL;
+       unsigned int format_flags;
+       int error;
+
+       format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY;
+
+       if ((error = git_diff_get_stats(&stats, diff)) == 0 &&
+           (error = git_diff_stats_to_buf(out, stats, format_flags, 0)) == 0)
+               error = git_buf_putc(out, '\n');
+
+       git_diff_stats_free(stats);
+       return error;
+}
+
+static int append_patches(git_buf *out, git_diff *diff)
+{
+       size_t i, deltas;
+       int error = 0;
+
+       deltas = git_diff_num_deltas(diff);
+
+       for (i = 0; i < deltas; ++i) {
+               git_patch *patch = NULL;
+
+               if ((error = git_patch_from_diff(&patch, diff, i)) >= 0)
+                       error = git_patch_to_buf(out, patch);
+
+               git_patch_free(patch);
+
+               if (error < 0)
+                       break;
+       }
+
+       return error;
+}
+
+int git_email__append_from_diff(
+       git_buf *out,
+       git_diff *diff,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const char *body,
+       const git_signature *author,
+       const git_email_create_options *given_opts)
+{
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diff);
+       GIT_ASSERT_ARG(!patch_idx || patch_idx <= patch_count);
+       GIT_ASSERT_ARG(commit_id);
+       GIT_ASSERT_ARG(author);
+
+       GIT_ERROR_CHECK_VERSION(given_opts,
+               GIT_EMAIL_CREATE_OPTIONS_VERSION,
+               "git_email_create_options");
+
+       if (given_opts)
+               memcpy(&opts, given_opts, sizeof(git_email_create_options));
+
+       git_buf_sanitize(out);
+
+       if ((error = append_header(out, patch_idx, patch_count, commit_id, summary, author, &opts)) == 0 &&
+           (error = append_body(out, body)) == 0 &&
+           (error = git_buf_puts(out, "---\n")) == 0 &&
+           (error = append_diffstat(out, diff)) == 0 &&
+           (error = append_patches(out, diff)) == 0)
+               error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
+
+       return error;
+}
+
+int git_email_create_from_diff(
+       git_buf *out,
+       git_diff *diff,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const char *body,
+       const git_signature *author,
+       const git_email_create_options *given_opts)
+{
+       int error;
+
+       git_buf_sanitize(out);
+       git_buf_clear(out);
+
+       error = git_email__append_from_diff(out, diff, patch_idx,
+               patch_count, commit_id, summary, body, author,
+               given_opts);
+
+       return error;
+}
+
+int git_email_create_from_commit(
+       git_buf *out,
+       git_commit *commit,
+       const git_email_create_options *given_opts)
+{
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+       git_diff *diff = NULL;
+       git_repository *repo;
+       git_diff_options *diff_opts;
+       git_diff_find_options *find_opts;
+       const git_signature *author;
+       const char *summary, *body;
+       const git_oid *commit_id;
+       int error = -1;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(commit);
+
+       GIT_ERROR_CHECK_VERSION(given_opts,
+               GIT_EMAIL_CREATE_OPTIONS_VERSION,
+               "git_email_create_options");
+
+       if (given_opts)
+               memcpy(&opts, given_opts, sizeof(git_email_create_options));
+
+       repo = git_commit_owner(commit);
+       author = git_commit_author(commit);
+       summary = git_commit_summary(commit);
+       body = git_commit_body(commit);
+       commit_id = git_commit_id(commit);
+       diff_opts = &opts.diff_opts;
+       find_opts = &opts.diff_find_opts;
+
+       if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0)
+               goto done;
+
+       if ((opts.flags & GIT_EMAIL_CREATE_NO_RENAMES) == 0 &&
+           (error = git_diff_find_similar(diff, find_opts)) < 0)
+               goto done;
+
+       error = git_email_create_from_diff(out, diff, 1, 1, commit_id, summary, body, author, &opts);
+
+done:
+       git_diff_free(diff);
+       return error;
+}
diff --git a/src/email.h b/src/email.h
new file mode 100644 (file)
index 0000000..7aeb462
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_email_h__
+#define INCLUDE_email_h__
+
+#include "common.h"
+
+#include "git2/email.h"
+
+extern int git_email__append_from_diff(
+       git_buf *out,
+       git_diff *diff,
+       size_t patch_idx,
+       size_t patch_count,
+       const git_oid *commit_id,
+       const char *summary,
+       const char *body,
+       const git_signature *author,
+       const git_email_create_options *given_opts);
+
+#endif
index 8570226b441d9c8eb10aaf099961fb3ef9821720..ce883b2dad17758ba3936b8c58d5f04f2a12a012 100644 (file)
@@ -7,9 +7,10 @@
 
 #include "common.h"
 
-#include "global.h"
+#include "threadstate.h"
 #include "posix.h"
 #include "buffer.h"
+#include "libgit2.h"
 
 /********************************************
  * New error handling
@@ -20,20 +21,25 @@ static git_error g_git_oom_error = {
        GIT_ERROR_NOMEMORY
 };
 
+static git_error g_git_uninitialized_error = {
+       "libgit2 has not been initialized; you must call git_libgit2_init",
+       GIT_ERROR_INVALID
+};
+
 static void set_error_from_buffer(int error_class)
 {
-       git_error *error = &GIT_GLOBAL->error_t;
-       git_buf *buf = &GIT_GLOBAL->error_buf;
+       git_error *error = &GIT_THREADSTATE->error_t;
+       git_buf *buf = &GIT_THREADSTATE->error_buf;
 
        error->message = buf->ptr;
        error->klass = error_class;
 
-       GIT_GLOBAL->last_error = error;
+       GIT_THREADSTATE->last_error = error;
 }
 
 static void set_error(int error_class, char *string)
 {
-       git_buf *buf = &GIT_GLOBAL->error_buf;
+       git_buf *buf = &GIT_THREADSTATE->error_buf;
 
        git_buf_clear(buf);
        if (string) {
@@ -46,7 +52,7 @@ static void set_error(int error_class, char *string)
 
 void git_error_set_oom(void)
 {
-       GIT_GLOBAL->last_error = &g_git_oom_error;
+       GIT_THREADSTATE->last_error = &g_git_oom_error;
 }
 
 void git_error_set(int error_class, const char *fmt, ...)
@@ -64,7 +70,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
        DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
 #endif
        int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
-       git_buf *buf = &GIT_GLOBAL->error_buf;
+       git_buf *buf = &GIT_THREADSTATE->error_buf;
 
        git_buf_clear(buf);
        if (fmt) {
@@ -97,14 +103,9 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
 
 int git_error_set_str(int error_class, const char *string)
 {
-       git_buf *buf = &GIT_GLOBAL->error_buf;
-
-       assert(string);
+       git_buf *buf = &GIT_THREADSTATE->error_buf;
 
-       if (!string) {
-               git_error_set(GIT_ERROR_INVALID, "unspecified caller error");
-               return -1;
-       }
+       GIT_ASSERT_ARG(string);
 
        git_buf_clear(buf);
        git_buf_puts(buf, string);
@@ -118,9 +119,9 @@ int git_error_set_str(int error_class, const char *string)
 
 void git_error_clear(void)
 {
-       if (GIT_GLOBAL->last_error != NULL) {
+       if (GIT_THREADSTATE->last_error != NULL) {
                set_error(0, NULL);
-               GIT_GLOBAL->last_error = NULL;
+               GIT_THREADSTATE->last_error = NULL;
        }
 
        errno = 0;
@@ -131,13 +132,17 @@ void git_error_clear(void)
 
 const git_error *git_error_last(void)
 {
-       return GIT_GLOBAL->last_error;
+       /* If the library is not initialized, return a static error. */
+       if (!git_libgit2_init_count())
+               return &g_git_uninitialized_error;
+
+       return GIT_THREADSTATE->last_error;
 }
 
 int git_error_state_capture(git_error_state *state, int error_code)
 {
-       git_error *error = GIT_GLOBAL->last_error;
-       git_buf *error_buf = &GIT_GLOBAL->error_buf;
+       git_error *error = GIT_THREADSTATE->last_error;
+       git_buf *error_buf = &GIT_THREADSTATE->error_buf;
 
        memset(state, 0, sizeof(git_error_state));
 
index e000de5e0c6f7f99a43dae7340f6faceef3945d2..202cef49ecb3b26983b872b957711ce666948276 100644 (file)
@@ -2,9 +2,12 @@
 #define INCLUDE_features_h__
 
 #cmakedefine GIT_DEBUG_POOL 1
+#cmakedefine GIT_DEBUG_STRICT_ALLOC 1
+#cmakedefine GIT_DEBUG_STRICT_OPEN 1
+
 #cmakedefine GIT_TRACE 1
 #cmakedefine GIT_THREADS 1
-#cmakedefine GIT_MSVC_CRTDBG 1
+#cmakedefine GIT_WIN32_LEAKCHECK 1
 
 #cmakedefine GIT_ARCH_64 1
 #cmakedefine GIT_ARCH_32 1
@@ -32,6 +35,7 @@
 #cmakedefine GIT_WINHTTP 1
 #cmakedefine GIT_HTTPS 1
 #cmakedefine GIT_OPENSSL 1
+#cmakedefine GIT_OPENSSL_DYNAMIC 1
 #cmakedefine GIT_SECURE_TRANSPORT 1
 #cmakedefine GIT_MBEDTLS 1
 
index f4a4c9f8170699611f3a8313445bd84bcb4eddc4..dedbb54fa5443e04ded887c61a3d9ab528c4d035 100644 (file)
 
 static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec, git_remote_autotag_option_t tagopt)
 {
-       int match = 0;
+       int match = 0, valid;
 
-       if (!git_reference_is_valid_name(head->name))
+       if (git_reference_name_is_valid(&valid, head->name) < 0)
+               return -1;
+
+       if (!valid)
                return 0;
 
        if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
index ea610f39a8f7768159d3307e31f64c05226b5a17..88c567e4847828a4261de2e1694bb8a8ce8024ff 100644 (file)
@@ -73,7 +73,8 @@ int git_fetchhead_ref_create(
 {
        git_fetchhead_ref *fetchhead_ref;
 
-       assert(out && oid);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(oid);
 
        *out = NULL;
 
@@ -108,7 +109,8 @@ static int fetchhead_ref_write(
        const char *type, *name;
        int head = 0;
 
-       assert(file && fetchhead_ref);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(fetchhead_ref);
 
        git_oid_fmt(oid, &fetchhead_ref->oid);
        oid[GIT_OID_HEXSZ] = '\0';
@@ -145,7 +147,8 @@ int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs)
        unsigned int i;
        git_fetchhead_ref *fetchhead_ref;
 
-       assert(repo && fetchhead_refs);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(fetchhead_refs);
 
        if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
                return -1;
@@ -279,7 +282,8 @@ int git_repository_fetchhead_foreach(git_repository *repo,
        size_t line_num = 0;
        int error = 0;
 
-       assert(repo && cb);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(cb);
 
        if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
                return -1;
index e12a9eabfea3bebf4bf9dbd6e9061c27dda49dae..a3f6b14839aa0bf50dfb466f92c25164598134cf 100644 (file)
@@ -184,7 +184,7 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
 
                } while (zs->avail_out == 0);
 
-               assert(zs->avail_in == 0);
+               GIT_ASSERT(zs->avail_in == 0);
 
                if (file->compute_digest)
                        git_hash_update(&file->digest, source, len);
@@ -278,10 +278,9 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo
        int compression, error = -1;
        size_t path_len, alloc_len;
 
-       /* opening an already open buffer is a programming error;
-        * assert that this never happens instead of returning
-        * an error code */
-       assert(file && path && file->buffer == NULL);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(path);
+       GIT_ASSERT(file->buffer == NULL);
 
        memset(file, 0x0, sizeof(git_filebuf));
 
@@ -389,7 +388,9 @@ cleanup:
 
 int git_filebuf_hash(git_oid *oid, git_filebuf *file)
 {
-       assert(oid && file && file->compute_digest);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(file->compute_digest);
 
        flush_buffer(file);
 
@@ -415,7 +416,8 @@ int git_filebuf_commit_at(git_filebuf *file, const char *path)
 int git_filebuf_commit(git_filebuf *file)
 {
        /* temporary files cannot be committed */
-       assert(file && file->path_original);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT(file->path_original);
 
        file->flush_mode = Z_FINISH;
        flush_buffer(file);
index 09b57dc80210e1e628f1b6dcc8dd2924ce490917..73497cb3024c2d4fa8301e169fab82dde08a4016 100644 (file)
@@ -11,7 +11,7 @@
 #include "futils.h"
 #include "hash.h"
 #include "repository.h"
-#include "global.h"
+#include "runtime.h"
 #include "git2/sys/filter.h"
 #include "git2/config.h"
 #include "blob.h"
 #include "array.h"
 
 struct git_filter_source {
-       git_repository *repo;
-       const char     *path;
-       git_oid         oid;  /* zero if unknown (which is likely) */
-       uint16_t        filemode; /* zero if unknown */
-       git_filter_mode_t mode;
-       uint32_t        flags;
+       git_repository    *repo;
+       const char        *path;
+       git_oid            oid;  /* zero if unknown (which is likely) */
+       uint16_t           filemode; /* zero if unknown */
+       git_filter_mode_t  mode;
+       git_filter_options options;
 };
 
 typedef struct {
@@ -206,7 +206,8 @@ int git_filter_global_init(void)
                        GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0)
                error = -1;
 
-       git__on_shutdown(git_filter_global_shutdown);
+       if (!error)
+               error = git_runtime_shutdown_register(git_filter_global_shutdown);
 
 done:
        if (error) {
@@ -266,7 +267,8 @@ int git_filter_register(
 {
        int error;
 
-       assert(name && filter);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(filter);
 
        if (git_rwlock_wrlock(&filter_registry.lock) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to lock filter registry");
@@ -293,7 +295,7 @@ int git_filter_unregister(const char *name)
        git_filter_def *fdef;
        int error = 0;
 
-       assert(name);
+       GIT_ASSERT_ARG(name);
 
        /* cannot unregister default filters */
        if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) {
@@ -395,7 +397,7 @@ git_filter_mode_t git_filter_source_mode(const git_filter_source *src)
 
 uint32_t git_filter_source_flags(const git_filter_source *src)
 {
-       return src->flags;
+       return src->options.flags;
 }
 
 static int filter_list_new(
@@ -415,7 +417,8 @@ static int filter_list_new(
        fl->source.repo = src->repo;
        fl->source.path = fl->path;
        fl->source.mode = src->mode;
-       fl->source.flags = src->flags;
+
+       memcpy(&fl->source.options, &src->options, sizeof(git_filter_options));
 
        *out = fl;
        return 0;
@@ -424,25 +427,36 @@ static int filter_list_new(
 static int filter_list_check_attributes(
        const char ***out,
        git_repository *repo,
-       git_attr_session *attr_session,
+       git_filter_session *filter_session,
        git_filter_def *fdef,
        const git_filter_source *src)
 {
        const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
-       uint32_t flags = 0;
+       git_attr_options attr_opts = GIT_ATTR_OPTIONS_INIT;
        size_t i;
        int error;
 
        GIT_ERROR_CHECK_ALLOC(strs);
 
-       if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
-               flags |= GIT_ATTR_CHECK_NO_SYSTEM;
+       if ((src->options.flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
+               attr_opts.flags |= GIT_ATTR_CHECK_NO_SYSTEM;
+
+       if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
+               attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
+
+       if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
+               attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_COMMIT;
 
-       if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
-               flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
+#ifndef GIT_DEPRECATE_HARD
+               if (src->options.commit_id)
+                       git_oid_cpy(&attr_opts.attr_commit_id, src->options.commit_id);
+               else
+#endif
+               git_oid_cpy(&attr_opts.attr_commit_id, &src->options.attr_commit_id);
+       }
 
        error = git_attr_get_many_with_session(
-               strs, repo, attr_session, flags, src->path, fdef->nattrs, fdef->attrs);
+               strs, repo, filter_session->attr_session, &attr_opts, src->path, fdef->nattrs, fdef->attrs);
 
        /* if no values were found but no matches are needed, it's okay! */
        if (error == GIT_ENOTFOUND && !fdef->nmatches) {
@@ -487,17 +501,17 @@ int git_filter_list_new(
        src.repo = repo;
        src.path = NULL;
        src.mode = mode;
-       src.flags = flags;
+       src.options.flags = flags;
        return filter_list_new(out, &src);
 }
 
-int git_filter_list__load_ext(
+int git_filter_list__load(
        git_filter_list **filters,
        git_repository *repo,
        git_blob *blob, /* can be NULL */
        const char *path,
        git_filter_mode_t mode,
-       git_filter_options *filter_opts)
+       git_filter_session *filter_session)
 {
        int error = 0;
        git_filter_list *fl = NULL;
@@ -514,7 +528,8 @@ int git_filter_list__load_ext(
        src.repo = repo;
        src.path = path;
        src.mode = mode;
-       src.flags = filter_opts->flags;
+
+       memcpy(&src.options, &filter_session->options, sizeof(git_filter_options));
 
        if (blob)
                git_oid_cpy(&src.oid, git_blob_id(blob));
@@ -528,7 +543,8 @@ int git_filter_list__load_ext(
 
                if (fdef->nattrs > 0) {
                        error = filter_list_check_attributes(
-                               &values, repo, filter_opts->attr_session, fdef, &src);
+                               &values, repo,
+                               filter_session, fdef, &src);
 
                        if (error == GIT_ENOTFOUND) {
                                error = 0;
@@ -555,7 +571,7 @@ int git_filter_list__load_ext(
                                if ((error = filter_list_new(&fl, &src)) < 0)
                                        break;
 
-                               fl->temp_buf = filter_opts->temp_buf;
+                               fl->temp_buf = filter_session->temp_buf;
                        }
 
                        fe = git_array_alloc(fl->filters);
@@ -579,6 +595,23 @@ int git_filter_list__load_ext(
        return error;
 }
 
+int git_filter_list_load_ext(
+       git_filter_list **filters,
+       git_repository *repo,
+       git_blob *blob, /* can be NULL */
+       const char *path,
+       git_filter_mode_t mode,
+       git_filter_options *opts)
+{
+       git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
+
+       if (opts)
+               memcpy(&filter_session.options, opts, sizeof(git_filter_options));
+
+       return git_filter_list__load(
+               filters, repo, blob, path, mode, &filter_session);
+}
+
 int git_filter_list_load(
        git_filter_list **filters,
        git_repository *repo,
@@ -587,12 +620,12 @@ int git_filter_list_load(
        git_filter_mode_t mode,
        uint32_t flags)
 {
-       git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
+       git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
 
-       filter_opts.flags = flags;
+       filter_session.options.flags = flags;
 
-       return git_filter_list__load_ext(
-               filters, repo, blob, path, mode, &filter_opts);
+       return git_filter_list__load(
+               filters, repo, blob, path, mode, &filter_session);
 }
 
 void git_filter_list_free(git_filter_list *fl)
@@ -618,7 +651,7 @@ int git_filter_list_contains(
 {
        size_t i;
 
-       assert(name);
+       GIT_ASSERT_ARG(name);
 
        if (!fl)
                return 0;
@@ -639,7 +672,8 @@ int git_filter_list_push(
        git_filter_def *fdef = NULL;
        git_filter_entry *fe;
 
-       assert(fl && filter);
+       GIT_ASSERT_ARG(fl);
+       GIT_ASSERT_ARG(filter);
 
        if (git_rwlock_rdlock(&filter_registry.lock) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to lock filter registry");
@@ -684,9 +718,8 @@ static int buf_stream_write(
        git_writestream *s, const char *buffer, size_t len)
 {
        struct buf_stream *buf_stream = (struct buf_stream *)s;
-       assert(buf_stream);
-
-       assert(buf_stream->complete == 0);
+       GIT_ASSERT_ARG(buf_stream);
+       GIT_ASSERT(buf_stream->complete == 0);
 
        return git_buf_put(buf_stream->target, buffer, len);
 }
@@ -694,9 +727,9 @@ static int buf_stream_write(
 static int buf_stream_close(git_writestream *s)
 {
        struct buf_stream *buf_stream = (struct buf_stream *)s;
-       assert(buf_stream);
+       GIT_ASSERT_ARG(buf_stream);
 
-       assert(buf_stream->complete == 0);
+       GIT_ASSERT(buf_stream->complete == 0);
        buf_stream->complete = 1;
 
        return 0;
@@ -719,27 +752,47 @@ static void buf_stream_init(struct buf_stream *writer, git_buf *target)
        git_buf_clear(target);
 }
 
-int git_filter_list_apply_to_data(
-       git_buf *tgt, git_filter_list *filters, git_buf *src)
+int git_filter_list_apply_to_buffer(
+       git_buf *out,
+       git_filter_list *filters,
+       const char *in,
+       size_t in_len)
 {
        struct buf_stream writer;
        int error;
 
-       git_buf_sanitize(tgt);
-       git_buf_sanitize(src);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
-       if (!filters) {
-               git_buf_attach_notowned(tgt, src->ptr, src->size);
+       buf_stream_init(&writer, out);
+
+       if ((error = git_filter_list_stream_buffer(filters,
+               in, in_len, &writer.parent)) < 0)
+                       return error;
+
+       GIT_ASSERT(writer.complete);
+       return error;
+}
+
+int git_filter_list__convert_buf(
+       git_buf *out,
+       git_filter_list *filters,
+       git_buf *in)
+{
+       int error;
+
+       if (!filters || git_filter_list_length(filters) == 0) {
+               git_buf_swap(out, in);
+               git_buf_dispose(in);
                return 0;
        }
 
-       buf_stream_init(&writer, tgt);
+       error = git_filter_list_apply_to_buffer(out, filters,
+               in->ptr, in->size);
 
-       if ((error = git_filter_list_stream_data(filters, src,
-               &writer.parent)) < 0)
-                       return error;
+       if (!error)
+               git_buf_dispose(in);
 
-       assert(writer.complete);
        return error;
 }
 
@@ -758,7 +811,7 @@ int git_filter_list_apply_to_file(
                filters, repo, path, &writer.parent)) < 0)
                        return error;
 
-       assert(writer.complete);
+       GIT_ASSERT(writer.complete);
        return error;
 }
 
@@ -789,13 +842,14 @@ int git_filter_list_apply_to_blob(
                filters, blob, &writer.parent)) < 0)
                        return error;
 
-       assert(writer.complete);
+       GIT_ASSERT(writer.complete);
        return error;
 }
 
-struct proxy_stream {
+struct buffered_stream {
        git_writestream parent;
        git_filter *filter;
+       int (*write_fn)(git_filter *, void **, git_buf *, const git_buf *, const git_filter_source *);
        const git_filter_source *source;
        void **payload;
        git_buf input;
@@ -804,89 +858,120 @@ struct proxy_stream {
        git_writestream *target;
 };
 
-static int proxy_stream_write(
+static int buffered_stream_write(
        git_writestream *s, const char *buffer, size_t len)
 {
-       struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
-       assert(proxy_stream);
+       struct buffered_stream *buffered_stream = (struct buffered_stream *)s;
+       GIT_ASSERT_ARG(buffered_stream);
 
-       return git_buf_put(&proxy_stream->input, buffer, len);
+       return git_buf_put(&buffered_stream->input, buffer, len);
 }
 
-static int proxy_stream_close(git_writestream *s)
+static int buffered_stream_close(git_writestream *s)
 {
-       struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
+       struct buffered_stream *buffered_stream = (struct buffered_stream *)s;
        git_buf *writebuf;
        git_error_state error_state = {0};
        int error;
 
-       assert(proxy_stream);
+       GIT_ASSERT_ARG(buffered_stream);
 
-       error = proxy_stream->filter->apply(
-               proxy_stream->filter,
-               proxy_stream->payload,
-               proxy_stream->output,
-               &proxy_stream->input,
-               proxy_stream->source);
+       error = buffered_stream->write_fn(
+               buffered_stream->filter,
+               buffered_stream->payload,
+               buffered_stream->output,
+               &buffered_stream->input,
+               buffered_stream->source);
 
        if (error == GIT_PASSTHROUGH) {
-               writebuf = &proxy_stream->input;
+               writebuf = &buffered_stream->input;
        } else if (error == 0) {
-               git_buf_sanitize(proxy_stream->output);
-               writebuf = proxy_stream->output;
+               if ((error = git_buf_sanitize(buffered_stream->output)) < 0)
+                       return error;
+
+               writebuf = buffered_stream->output;
        } else {
                /* close stream before erroring out taking care
                 * to preserve the original error */
                git_error_state_capture(&error_state, error);
-               proxy_stream->target->close(proxy_stream->target);
+               buffered_stream->target->close(buffered_stream->target);
                git_error_state_restore(&error_state);
                return error;
        }
 
-       if ((error = proxy_stream->target->write(
-                       proxy_stream->target, writebuf->ptr, writebuf->size)) == 0)
-               error = proxy_stream->target->close(proxy_stream->target);
+       if ((error = buffered_stream->target->write(
+                       buffered_stream->target, writebuf->ptr, writebuf->size)) == 0)
+               error = buffered_stream->target->close(buffered_stream->target);
 
        return error;
 }
 
-static void proxy_stream_free(git_writestream *s)
+static void buffered_stream_free(git_writestream *s)
 {
-       struct proxy_stream *proxy_stream = (struct proxy_stream *)s;
-       assert(proxy_stream);
+       struct buffered_stream *buffered_stream = (struct buffered_stream *)s;
 
-       git_buf_dispose(&proxy_stream->input);
-       git_buf_dispose(&proxy_stream->temp_buf);
-       git__free(proxy_stream);
+       if (buffered_stream) {
+               git_buf_dispose(&buffered_stream->input);
+               git_buf_dispose(&buffered_stream->temp_buf);
+               git__free(buffered_stream);
+       }
 }
 
-static int proxy_stream_init(
+int git_filter_buffered_stream_new(
        git_writestream **out,
        git_filter *filter,
+       int (*write_fn)(git_filter *, void **, git_buf *, const git_buf *, const git_filter_source *),
        git_buf *temp_buf,
        void **payload,
        const git_filter_source *source,
        git_writestream *target)
 {
-       struct proxy_stream *proxy_stream = git__calloc(1, sizeof(struct proxy_stream));
-       GIT_ERROR_CHECK_ALLOC(proxy_stream);
-
-       proxy_stream->parent.write = proxy_stream_write;
-       proxy_stream->parent.close = proxy_stream_close;
-       proxy_stream->parent.free = proxy_stream_free;
-       proxy_stream->filter = filter;
-       proxy_stream->payload = payload;
-       proxy_stream->source = source;
-       proxy_stream->target = target;
-       proxy_stream->output = temp_buf ? temp_buf : &proxy_stream->temp_buf;
+       struct buffered_stream *buffered_stream = git__calloc(1, sizeof(struct buffered_stream));
+       GIT_ERROR_CHECK_ALLOC(buffered_stream);
+
+       buffered_stream->parent.write = buffered_stream_write;
+       buffered_stream->parent.close = buffered_stream_close;
+       buffered_stream->parent.free = buffered_stream_free;
+       buffered_stream->filter = filter;
+       buffered_stream->write_fn = write_fn;
+       buffered_stream->output = temp_buf ? temp_buf : &buffered_stream->temp_buf;
+       buffered_stream->payload = payload;
+       buffered_stream->source = source;
+       buffered_stream->target = target;
 
        if (temp_buf)
                git_buf_clear(temp_buf);
 
-       *out = (git_writestream *)proxy_stream;
+       *out = (git_writestream *)buffered_stream;
        return 0;
 }
 
+static int setup_stream(
+       git_writestream **out,
+       git_filter_entry *fe,
+       git_filter_list *filters,
+       git_writestream *last_stream)
+{
+#ifndef GIT_DEPRECATE_HARD
+       GIT_ASSERT(fe->filter->stream || fe->filter->apply);
+
+       /*
+        * If necessary, create a stream that proxies the traditional
+        * application.
+        */
+       if (!fe->filter->stream) {
+               /* Create a stream that proxies the one-shot apply */
+               return git_filter_buffered_stream_new(out,
+                       fe->filter, fe->filter->apply, filters->temp_buf,
+                       &fe->payload, &filters->source, last_stream);
+       }
+#endif
+
+       GIT_ASSERT(fe->filter->stream);
+       return fe->filter->stream(out, fe->filter,
+               &fe->payload, &filters->source, last_stream);
+}
+
 static int stream_list_init(
        git_writestream **out,
        git_vector *streams,
@@ -908,22 +993,11 @@ static int stream_list_init(
        for (i = 0; i < git_array_size(filters->filters); ++i) {
                size_t filter_idx = (filters->source.mode == GIT_FILTER_TO_WORKTREE) ?
                        git_array_size(filters->filters) - 1 - i : i;
+
                git_filter_entry *fe = git_array_get(filters->filters, filter_idx);
                git_writestream *filter_stream;
 
-               assert(fe->filter->stream || fe->filter->apply);
-
-               /* If necessary, create a stream that proxies the traditional
-                * application.
-                */
-               if (fe->filter->stream)
-                       error = fe->filter->stream(&filter_stream, fe->filter,
-                               &fe->payload, &filters->source, last_stream);
-               else
-                       /* Create a stream that proxies the one-shot apply */
-                       error = proxy_stream_init(&filter_stream, fe->filter,
-                               filters->temp_buf, &fe->payload, &filters->source,
-                               last_stream);
+               error = setup_stream(&filter_stream, fe, filters, last_stream);
 
                if (error < 0)
                        goto out;
@@ -967,8 +1041,10 @@ int git_filter_list_stream_file(
 
        if ((error = stream_list_init(
                        &stream_start, &filter_streams, filters, target)) < 0 ||
-               (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0)
+           (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0 ||
+           (error = git_path_validate_workdir_buf(repo, &abspath)) < 0)
                goto done;
+
        initialized = 1;
 
        if ((fd = git_futils_open_ro(abspath.ptr)) < 0) {
@@ -995,23 +1071,21 @@ done:
        return error;
 }
 
-int git_filter_list_stream_data(
+int git_filter_list_stream_buffer(
        git_filter_list *filters,
-       git_buf *data,
+       const char *buffer,
+       size_t len,
        git_writestream *target)
 {
        git_vector filter_streams = GIT_VECTOR_INIT;
        git_writestream *stream_start;
        int error, initialized = 0;
 
-       git_buf_sanitize(data);
-
        if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0)
                goto out;
        initialized = 1;
 
-       if ((error = stream_start->write(
-                       stream_start, data->ptr, data->size)) < 0)
+       if ((error = stream_start->write(stream_start, buffer, len)) < 0)
                goto out;
 
 out:
@@ -1035,7 +1109,7 @@ int git_filter_list_stream_blob(
        if (filters)
                git_oid_cpy(&filters->source.oid, git_blob_id(blob));
 
-       return git_filter_list_stream_data(filters, &in, target);
+       return git_filter_list_stream_buffer(filters, in.ptr, in.size, target);
 }
 
 int git_filter_init(git_filter *filter, unsigned int version)
@@ -1043,3 +1117,31 @@ int git_filter_init(git_filter *filter, unsigned int version)
        GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter, version, git_filter, GIT_FILTER_INIT);
        return 0;
 }
+
+#ifndef GIT_DEPRECATE_HARD
+
+int git_filter_list_stream_data(
+       git_filter_list *filters,
+       git_buf *data,
+       git_writestream *target)
+{
+       int error;
+
+       if ((error = git_buf_sanitize(data)) < 0)
+               return error;
+
+       return git_filter_list_stream_buffer(filters, data->ptr, data->size, target);
+}
+
+int git_filter_list_apply_to_data(
+       git_buf *tgt, git_filter_list *filters, git_buf *src)
+{
+       int error;
+
+       if ((error = git_buf_sanitize(src)) < 0)
+           return error;
+
+       return git_filter_list_apply_to_buffer(tgt, filters, src->ptr, src->size);
+}
+
+#endif
index 34081fb4adfb017af9ebe622c06c6760183f7e80..241791276cd1f1dc603514f915744a5471a3d979 100644 (file)
 
 #include "attr_file.h"
 #include "git2/filter.h"
+#include "git2/sys/filter.h"
 
 /* Amount of file to examine for NUL byte when checking binary-ness */
 #define GIT_FILTER_BYTES_TO_CHECK_NUL 8000
 
 typedef struct {
+       git_filter_options options;
        git_attr_session *attr_session;
        git_buf *temp_buf;
-       uint32_t flags;
-} git_filter_options;
+} git_filter_session;
 
-#define GIT_FILTER_OPTIONS_INIT {0}
+#define GIT_FILTER_SESSION_INIT {GIT_FILTER_OPTIONS_INIT, 0}
 
 extern int git_filter_global_init(void);
 
 extern void git_filter_free(git_filter *filter);
 
-extern int git_filter_list__load_ext(
+extern int git_filter_list__load(
        git_filter_list **filters,
        git_repository *repo,
        git_blob *blob, /* can be NULL */
        const char *path,
        git_filter_mode_t mode,
-       git_filter_options *filter_opts);
+       git_filter_session *filter_session);
+
+/*
+ * The given input buffer will be converted to the given output buffer.
+ * The input buffer will be freed (_if_ it was allocated).
+ */
+extern int git_filter_list__convert_buf(
+       git_buf *out,
+       git_filter_list *filters,
+       git_buf *in);
 
 /*
  * Available filters
@@ -42,4 +52,13 @@ extern int git_filter_list__load_ext(
 extern git_filter *git_crlf_filter_new(void);
 extern git_filter *git_ident_filter_new(void);
 
+extern int git_filter_buffered_stream_new(
+       git_writestream **out,
+       git_filter *filter,
+       int (*write_fn)(git_filter *, void **, git_buf *, const git_buf *, const git_filter_source *),
+       git_buf *temp_buf,
+       void **payload,
+       const git_filter_source *source,
+       git_writestream *target);
+
 #endif
index 8c0f008b3315ce1ce54f8e89bd36020da7587da1..a44820875b16fe91046a81e3d2da65691be83bde 100644 (file)
@@ -7,8 +7,9 @@
 
 #include "futils.h"
 
-#include "global.h"
+#include "runtime.h"
 #include "strmap.h"
+#include "hash.h"
 #include <ctype.h>
 #if GIT_WIN32
 #include "win32/findfile.h"
@@ -184,7 +185,8 @@ int git_futils_readbuffer_updated(
        git_buf buf = GIT_BUF_INIT;
        git_oid checksum_new;
 
-       assert(out && path && *path);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(path && *path);
 
        if (updated != NULL)
                *updated = 0;
@@ -492,7 +494,7 @@ int git_futils_mkdir(
                        goto done;
                }
 
-               assert(len);
+               GIT_ASSERT(len);
 
                /*
                 * We've walked all the given path's parents and it's either relative
@@ -1127,8 +1129,6 @@ int git_futils_filestamp_check(
 void git_futils_filestamp_set(
        git_futils_filestamp *target, const git_futils_filestamp *source)
 {
-       assert(target);
-
        if (source)
                memcpy(target, source, sizeof(*target));
        else
index 4668d7b63cf2e0add6607753d4479223540a0229..58936125ac2898e893c0004505533d623644180c 100644 (file)
@@ -257,7 +257,7 @@ extern int git_futils_truncate(const char *path, int mode);
  */
 extern int git_futils_filesize(uint64_t *out, git_file fd);
 
-#define GIT_PERMS_IS_EXEC(MODE)                (((MODE) & 0111) != 0)
+#define GIT_PERMS_IS_EXEC(MODE)                (((MODE) & 0100) != 0)
 #define GIT_PERMS_CANONICAL(MODE)      (GIT_PERMS_IS_EXEC(MODE) ? 0755 : 0644)
 #define GIT_PERMS_FOR_WRITE(MODE)   (GIT_PERMS_IS_EXEC(MODE) ? 0777 : 0666)
 
diff --git a/src/global.c b/src/global.c
deleted file mode 100644 (file)
index 9fe8cd5..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "global.h"
-
-#include "alloc.h"
-#include "hash.h"
-#include "sysdir.h"
-#include "filter.h"
-#include "merge_driver.h"
-#include "pool.h"
-#include "streams/registry.h"
-#include "streams/mbedtls.h"
-#include "streams/openssl.h"
-#include "thread-utils.h"
-#include "git2/global.h"
-#include "transports/ssh.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-#include "win32/w32_stack.h"
-#include "win32/w32_crtdbg_stacktrace.h"
-#endif
-
-git_mutex git__mwindow_mutex;
-
-typedef int (*git_global_init_fn)(void);
-
-static git_global_init_fn git__init_callbacks[] = {
-       git_allocator_global_init,
-       git_hash_global_init,
-       git_sysdir_global_init,
-       git_filter_global_init,
-       git_merge_driver_global_init,
-       git_transport_ssh_global_init,
-       git_stream_registry_global_init,
-       git_openssl_stream_global_init,
-       git_mbedtls_stream_global_init,
-       git_mwindow_global_init,
-       git_pool_global_init
-};
-
-static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];
-
-static git_atomic git__n_shutdown_callbacks;
-static git_atomic git__n_inits;
-char *git__user_agent;
-char *git__ssl_ciphers;
-
-void git__on_shutdown(git_global_shutdown_fn callback)
-{
-       int count = git_atomic_inc(&git__n_shutdown_callbacks);
-       assert(count <= (int) ARRAY_SIZE(git__shutdown_callbacks) && count > 0);
-       git__shutdown_callbacks[count - 1] = callback;
-}
-
-static void git__global_state_cleanup(git_global_st *st)
-{
-       if (!st)
-               return;
-
-       git__free(st->error_t.message);
-       st->error_t.message = NULL;
-}
-
-static int init_common(void)
-{
-       size_t i;
-       int ret;
-
-       /* Initialize the CRT debug allocator first, before our first malloc */
-#if defined(GIT_MSVC_CRTDBG)
-       git_win32__crtdbg_stacktrace_init();
-       git_win32__stack_init();
-#endif
-
-       /* Initialize subsystems that have global state */
-       for (i = 0; i < ARRAY_SIZE(git__init_callbacks); i++)
-               if ((ret = git__init_callbacks[i]()) != 0)
-                       break;
-
-       GIT_MEMORY_BARRIER;
-
-       return ret;
-}
-
-static void shutdown_common(void)
-{
-       int pos;
-
-       /* Shutdown subsystems that have registered */
-       for (pos = git_atomic_get(&git__n_shutdown_callbacks);
-               pos > 0;
-               pos = git_atomic_dec(&git__n_shutdown_callbacks)) {
-
-               git_global_shutdown_fn cb = git__swap(
-                       git__shutdown_callbacks[pos - 1], NULL);
-
-               if (cb != NULL)
-                       cb();
-       }
-
-       git__free(git__user_agent);
-       git__free(git__ssl_ciphers);
-}
-
-/**
- * Handle the global state with TLS
- *
- * If libgit2 is built with GIT_THREADS enabled,
- * the `git_libgit2_init()` function must be called
- * before calling any other function of the library.
- *
- * This function allocates a TLS index (using pthreads
- * or the native Win32 API) to store the global state
- * on a per-thread basis.
- *
- * Any internal method that requires global state will
- * then call `git__global_state()` which returns a pointer
- * to the global state structure; this pointer is lazily
- * allocated on each thread.
- *
- * Before shutting down the library, the
- * `git_libgit2_shutdown` method must be called to free
- * the previously reserved TLS index.
- *
- * If libgit2 is built without threading support, the
- * `git__global_statestate()` call returns a pointer to a single,
- * statically allocated global state. The `git_thread_`
- * functions are not available in that case.
- */
-
-/*
- * `git_libgit2_init()` allows subsystems to perform global setup,
- * which may take place in the global scope.  An explicit memory
- * fence exists at the exit of `git_libgit2_init()`.  Without this,
- * CPU cores are free to reorder cache invalidation of `_tls_init`
- * before cache invalidation of the subsystems' newly written global
- * state.
- */
-#if defined(GIT_THREADS) && defined(GIT_WIN32)
-
-static DWORD _fls_index;
-static volatile LONG _mutex = 0;
-
-static void WINAPI fls_free(void *st)
-{
-       git__global_state_cleanup(st);
-       git__free(st);
-}
-
-static int synchronized_threads_init(void)
-{
-       int error;
-
-       if ((_fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
-               return -1;
-
-       git_threads_init();
-
-       if (git_mutex_init(&git__mwindow_mutex))
-               return -1;
-
-       error = init_common();
-
-       return error;
-}
-
-int git_libgit2_init(void)
-{
-       int ret;
-
-       /* Enter the lock */
-       while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
-
-       /* Only do work on a 0 -> 1 transition of the refcount */
-       if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
-               if (synchronized_threads_init() < 0)
-                       ret = -1;
-       }
-
-       /* Exit the lock */
-       InterlockedExchange(&_mutex, 0);
-
-       return ret;
-}
-
-int git_libgit2_shutdown(void)
-{
-       int ret;
-
-       /* Enter the lock */
-       while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
-
-       /* Only do work on a 1 -> 0 transition of the refcount */
-       if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
-               shutdown_common();
-
-               FlsFree(_fls_index);
-               git_mutex_free(&git__mwindow_mutex);
-
-#if defined(GIT_MSVC_CRTDBG)
-               git_win32__crtdbg_stacktrace_cleanup();
-               git_win32__stack_cleanup();
-#endif
-       }
-
-       /* Exit the lock */
-       InterlockedExchange(&_mutex, 0);
-
-       return ret;
-}
-
-git_global_st *git__global_state(void)
-{
-       git_global_st *ptr;
-
-       assert(git_atomic_get(&git__n_inits) > 0);
-
-       if ((ptr = FlsGetValue(_fls_index)) != NULL)
-               return ptr;
-
-       ptr = git__calloc(1, sizeof(git_global_st));
-       if (!ptr)
-               return NULL;
-
-       git_buf_init(&ptr->error_buf, 0);
-
-       FlsSetValue(_fls_index, ptr);
-       return ptr;
-}
-
-#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
-
-static pthread_key_t _tls_key;
-static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
-int init_error = 0;
-
-static void cb__free_status(void *st)
-{
-       git__global_state_cleanup(st);
-       git__free(st);
-}
-
-static void init_once(void)
-{
-       if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
-               return;
-
-       pthread_key_create(&_tls_key, &cb__free_status);
-
-       init_error = init_common();
-}
-
-int git_libgit2_init(void)
-{
-       int ret, err;
-
-       if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
-               return err;
-
-       ret = git_atomic_inc(&git__n_inits);
-       err = pthread_once(&_once_init, init_once);
-       err |= pthread_mutex_unlock(&_init_mutex);
-
-       if (err || init_error)
-               return err | init_error;
-
-       return ret;
-}
-
-int git_libgit2_shutdown(void)
-{
-       void *ptr = NULL;
-       pthread_once_t new_once = PTHREAD_ONCE_INIT;
-       int error, ret;
-
-       if ((error = pthread_mutex_lock(&_init_mutex)) != 0)
-               return error;
-
-       if ((ret = git_atomic_dec(&git__n_inits)) != 0)
-               goto out;
-
-       /* Shut down any subsystems that have global state */
-       shutdown_common();
-
-       ptr = pthread_getspecific(_tls_key);
-       pthread_setspecific(_tls_key, NULL);
-
-       git__global_state_cleanup(ptr);
-       git__free(ptr);
-
-       pthread_key_delete(_tls_key);
-       git_mutex_free(&git__mwindow_mutex);
-       _once_init = new_once;
-
-out:
-       if ((error = pthread_mutex_unlock(&_init_mutex)) != 0)
-               return error;
-
-       return ret;
-}
-
-git_global_st *git__global_state(void)
-{
-       git_global_st *ptr;
-
-       assert(git_atomic_get(&git__n_inits) > 0);
-
-       if ((ptr = pthread_getspecific(_tls_key)) != NULL)
-               return ptr;
-
-       ptr = git__calloc(1, sizeof(git_global_st));
-       if (!ptr)
-               return NULL;
-
-       git_buf_init(&ptr->error_buf, 0);
-       pthread_setspecific(_tls_key, ptr);
-       return ptr;
-}
-
-#else
-
-static git_global_st __state;
-
-int git_libgit2_init(void)
-{
-       int ret;
-
-       /* Only init subsystems the first time */
-       if ((ret = git_atomic_inc(&git__n_inits)) != 1)
-               return ret;
-
-       if ((ret = init_common()) < 0)
-               return ret;
-
-       return 1;
-}
-
-int git_libgit2_shutdown(void)
-{
-       int ret;
-
-       /* Shut down any subsystems that have global state */
-       if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
-               shutdown_common();
-               git__global_state_cleanup(&__state);
-               memset(&__state, 0, sizeof(__state));
-       }
-
-       return ret;
-}
-
-git_global_st *git__global_state(void)
-{
-       return &__state;
-}
-
-#endif /* GIT_THREADS */
diff --git a/src/global.h b/src/global.h
deleted file mode 100644 (file)
index db41dad..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_global_h__
-#define INCLUDE_global_h__
-
-#include "common.h"
-
-#include "mwindow.h"
-#include "hash.h"
-
-typedef struct {
-       git_error *last_error;
-       git_error error_t;
-       git_buf error_buf;
-       char oid_fmt[GIT_OID_HEXSZ+1];
-
-       /* On Windows, this is the current child thread that was started by
-        * `git_thread_create`.  This is used to set the thread's exit code
-        * when terminated by `git_thread_exit`.  It is unused on POSIX.
-        */
-       git_thread *current_thread;
-} git_global_st;
-
-git_global_st *git__global_state(void);
-
-extern git_mutex git__mwindow_mutex;
-
-#define GIT_GLOBAL (git__global_state())
-
-typedef void (*git_global_shutdown_fn)(void);
-
-extern void git__on_shutdown(git_global_shutdown_fn callback);
-
-extern const char *git_libgit2__user_agent(void);
-extern const char *git_libgit2__ssl_ciphers(void);
-
-#endif
index df82f0f713d1445fbde590ace61ab9e636dd1ddc..35e914f7462d9572524a548e3086757f79cb2e10 100644 (file)
@@ -43,7 +43,7 @@ static int mark_parents(git_revwalk *walk, git_commit_list_node *one,
                return 0;
        }
 
-       if (git_pqueue_init(&list, 0, 2, git_commit_list_time_cmp) < 0)
+       if (git_pqueue_init(&list, 0, 2, git_commit_list_generation_cmp) < 0)
                return -1;
 
        if (git_commit_list_parse(walk, one) < 0)
@@ -176,19 +176,74 @@ on_error:
 
 int git_graph_descendant_of(git_repository *repo, const git_oid *commit, const git_oid *ancestor)
 {
-       git_oid merge_base;
-       int error;
-
        if (git_oid_equal(commit, ancestor))
                return 0;
 
-       error = git_merge_base(&merge_base, repo, commit, ancestor);
-       /* No merge-base found, it's not a descendant */
-       if (error == GIT_ENOTFOUND)
+       return git_graph_reachable_from_any(repo, ancestor, commit, 1);
+}
+
+int git_graph_reachable_from_any(
+               git_repository *repo,
+               const git_oid *commit_id,
+               const git_oid descendant_array[],
+               size_t length)
+{
+       git_revwalk *walk = NULL;
+       git_vector list;
+       git_commit_list *result = NULL;
+       git_commit_list_node *commit;
+       size_t i;
+       uint32_t minimum_generation = 0xffffffff;
+       int error = 0;
+
+       if (!length)
                return 0;
 
-       if (error < 0)
+       for (i = 0; i < length; ++i) {
+               if (git_oid_equal(commit_id, &descendant_array[i]))
+                       return 1;
+       }
+
+       if ((error = git_vector_init(&list, length + 1, NULL)) < 0)
                return error;
 
-       return git_oid_equal(&merge_base, ancestor);
+       if ((error = git_revwalk_new(&walk, repo)) < 0)
+               goto done;
+
+       for (i = 0; i < length; i++) {
+               commit = git_revwalk__commit_lookup(walk, &descendant_array[i]);
+               if (commit == NULL) {
+                       error = -1;
+                       goto done;
+               }
+
+               git_vector_insert(&list, commit);
+               if (minimum_generation > commit->generation)
+                       minimum_generation = commit->generation;
+       }
+
+       commit = git_revwalk__commit_lookup(walk, commit_id);
+       if (commit == NULL) {
+               error = -1;
+               goto done;
+       }
+
+       if (minimum_generation > commit->generation)
+               minimum_generation = commit->generation;
+
+       if ((error = git_merge__bases_many(&result, walk, commit, &list, minimum_generation)) < 0)
+               goto done;
+
+       if (result) {
+               error = git_oid_equal(commit_id, &result->item->oid);
+       } else {
+               /* No merge-base found, it's not a descendant */
+               error = 0;
+       }
+
+done:
+       git_commit_list_free(&result);
+       git_vector_free(&list);
+       git_revwalk_free(walk);
+       return error;
 }
index 405c46a9acb5080aa6e5bec3bd5e4112eadf9b69..5a7278e4225673a9f615dc6fa2144a811eaf82eb 100644 (file)
@@ -16,7 +16,7 @@ int git_hash_ctx_init(git_hash_ctx *ctx)
 {
        int error;
 
-       if ((error = git_hash_sha1_ctx_init(&ctx->sha1)) < 0)
+       if ((error = git_hash_sha1_ctx_init(&ctx->ctx.sha1)) < 0)
                return error;
 
        ctx->algo = GIT_HASH_ALGO_SHA1;
@@ -28,10 +28,10 @@ void git_hash_ctx_cleanup(git_hash_ctx *ctx)
 {
        switch (ctx->algo) {
                case GIT_HASH_ALGO_SHA1:
-                       git_hash_sha1_ctx_cleanup(&ctx->sha1);
+                       git_hash_sha1_ctx_cleanup(&ctx->ctx.sha1);
                        return;
                default:
-                       assert(0);
+                       /* unreachable */ ;
        }
 }
 
@@ -39,33 +39,36 @@ int git_hash_init(git_hash_ctx *ctx)
 {
        switch (ctx->algo) {
                case GIT_HASH_ALGO_SHA1:
-                       return git_hash_sha1_init(&ctx->sha1);
+                       return git_hash_sha1_init(&ctx->ctx.sha1);
                default:
-                       assert(0);
-                       return -1;
+                       /* unreachable */ ;
        }
+       GIT_ASSERT(0);
+       return -1;
 }
 
 int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
 {
        switch (ctx->algo) {
                case GIT_HASH_ALGO_SHA1:
-                       return git_hash_sha1_update(&ctx->sha1, data, len);
+                       return git_hash_sha1_update(&ctx->ctx.sha1, data, len);
                default:
-                       assert(0);
-                       return -1;
+                       /* unreachable */ ;
        }
+       GIT_ASSERT(0);
+       return -1;
 }
 
 int git_hash_final(git_oid *out, git_hash_ctx *ctx)
 {
        switch (ctx->algo) {
                case GIT_HASH_ALGO_SHA1:
-                       return git_hash_sha1_final(out, &ctx->sha1);
+                       return git_hash_sha1_final(out, &ctx->ctx.sha1);
                default:
-                       assert(0);
-                       return -1;
+                       /* unreachable */ ;
        }
+       GIT_ASSERT(0);
+       return -1;
 }
 
 int git_hash_buf(git_oid *out, const void *data, size_t len)
@@ -80,7 +83,7 @@ int git_hash_buf(git_oid *out, const void *data, size_t len)
                error = git_hash_final(out, &ctx);
 
        git_hash_ctx_cleanup(&ctx);
-       
+
        return error;
 }
 
index 017bb286c34d4abf734f8cdb27e82822a1dfc271..87305cc79201eead205d62da06978469ad8fd219 100644 (file)
@@ -27,7 +27,7 @@ typedef enum {
 typedef struct git_hash_ctx {
        union {
                git_hash_sha1_ctx sha1;
-       };
+       } ctx;
        git_hash_algo_t algo;
 } git_hash_ctx;
 
index e6a126780a12e0143807301b0401ae42a41bbedf..722ebf36f3814be04fccfd8cd6b83bc6b30f6ea0 100644 (file)
@@ -24,21 +24,21 @@ void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
 
 int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        SHA1DCInit(&ctx->c);
        return 0;
 }
 
 int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        SHA1DCUpdate(&ctx->c, data, len);
        return 0;
 }
 
 int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        if (SHA1DCFinal(out->id, &ctx->c)) {
                git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected");
                return -1;
index 0449a3c9dff14ae1632d840bd499a5a1bf850eb2..4250e0b614fb1a3cd3f8b8e13dddd50645cdac5b 100644 (file)
@@ -26,7 +26,7 @@ void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
 
 int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        CC_SHA1_Init(&ctx->c);
        return 0;
 }
@@ -35,7 +35,7 @@ int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len)
 {
        const unsigned char *data = _data;
 
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        while (len > 0) {
                CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
@@ -51,7 +51,7 @@ int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len)
 
 int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        CC_SHA1_Final(out->id, &ctx->c);
        return 0;
 }
index e4cc6026b955395448d6c8ca2dfce216f06a64c8..53fc0823e061a813cce19833e514b317c7e0d9cd 100644 (file)
@@ -11,7 +11,7 @@
 #include "hash/sha1.h"
 
 struct git_hash_sha1_ctx {
-       unsigned long long size;
+       uint64_t size;
        unsigned int H[5];
        unsigned int W[16];
 };
index e44343fcf3c04fabeeb3f157eca3324bc110f612..04e7da5facb58be68946f481cdb4f45cc58034a3 100644 (file)
@@ -19,28 +19,28 @@ int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
 
 void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
 {
-    assert(ctx);
-    mbedtls_sha1_free(&ctx->c);
+       if (ctx)
+               mbedtls_sha1_free(&ctx->c);
 }
 
 int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 {
-    assert(ctx);
-    mbedtls_sha1_init(&ctx->c);
-    mbedtls_sha1_starts(&ctx->c);
-    return 0;
+       GIT_ASSERT_ARG(ctx);
+       mbedtls_sha1_init(&ctx->c);
+       mbedtls_sha1_starts(&ctx->c);
+       return 0;
 }
 
 int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
 {
-    assert(ctx);
-    mbedtls_sha1_update(&ctx->c, data, len);
-    return 0;
+       GIT_ASSERT_ARG(ctx);
+       mbedtls_sha1_update(&ctx->c, data, len);
+       return 0;
 }
 
 int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
 {
-    assert(ctx);
-    mbedtls_sha1_finish(&ctx->c, out->id);
-    return 0;
+       GIT_ASSERT_ARG(ctx);
+       mbedtls_sha1_finish(&ctx->c, out->id);
+       return 0;
 }
index ba3212ff283fef78a7b709b858661b7760a4f110..68d9611d4adf44caa597c5b65285c00ed5cbe01f 100644 (file)
@@ -24,7 +24,7 @@ void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
 
 int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        if (SHA1_Init(&ctx->c) != 1) {
                git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context");
@@ -36,7 +36,7 @@ int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 
 int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        if (SHA1_Update(&ctx->c, data, len) != 1) {
                git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash");
@@ -48,7 +48,7 @@ int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
 
 int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        if (SHA1_Final(out->id, &ctx->c) != 1) {
                git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash");
index 9d3cf81d4d712f9dd31b86b5542c5cba0401633a..4d03c75d8c24510f5698256fca2ccc5ced673ef2 100644 (file)
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef __unix__
 #include <sys/types.h> /* make sure macros like _BIG_ENDIAN visible */
 #endif
-#endif
 
 #ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C
 #include SHA1DC_CUSTOM_INCLUDE_SHA1_C
@@ -1712,7 +1710,7 @@ static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t i
 
 
 
-static void sha1_process(SHA1_CTXctx, const uint32_t block[16])
+static void sha1_process(SHA1_CTX *ctx, const uint32_t block[16])
 {
        unsigned i, j;
        uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF };
@@ -1764,7 +1762,7 @@ static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16])
        }
 }
 
-void SHA1DCInit(SHA1_CTXctx)
+void SHA1DCInit(SHA1_CTX *ctx)
 {
        ctx->total = 0;
        ctx->ihv[0] = 0x67452301;
@@ -1780,7 +1778,7 @@ void SHA1DCInit(SHA1_CTX* ctx)
        ctx->callback = NULL;
 }
 
-void SHA1DCSetSafeHash(SHA1_CTXctx, int safehash)
+void SHA1DCSetSafeHash(SHA1_CTX *ctx, int safehash)
 {
        if (safehash)
                ctx->safe_hash = 1;
@@ -1789,7 +1787,7 @@ void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash)
 }
 
 
-void SHA1DCSetUseUBC(SHA1_CTXctx, int ubc_check)
+void SHA1DCSetUseUBC(SHA1_CTX *ctx, int ubc_check)
 {
        if (ubc_check)
                ctx->ubc_check = 1;
@@ -1797,7 +1795,7 @@ void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check)
                ctx->ubc_check = 0;
 }
 
-void SHA1DCSetUseDetectColl(SHA1_CTXctx, int detect_coll)
+void SHA1DCSetUseDetectColl(SHA1_CTX *ctx, int detect_coll)
 {
        if (detect_coll)
                ctx->detect_coll = 1;
@@ -1805,7 +1803,7 @@ void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll)
                ctx->detect_coll = 0;
 }
 
-void SHA1DCSetDetectReducedRoundCollision(SHA1_CTXctx, int reduced_round_coll)
+void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX *ctx, int reduced_round_coll)
 {
        if (reduced_round_coll)
                ctx->reduced_round_coll = 1;
@@ -1813,12 +1811,12 @@ void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll)
                ctx->reduced_round_coll = 0;
 }
 
-void SHA1DCSetCallback(SHA1_CTXctx, collision_block_callback callback)
+void SHA1DCSetCallback(SHA1_CTX *ctx, collision_block_callback callback)
 {
        ctx->callback = callback;
 }
 
-void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len)
+void SHA1DCUpdate(SHA1_CTX *ctx, const char *buf, size_t len)
 {
        unsigned left, fill;
 
index c7369566598c432629d9eadce4d5e6b7be18964e..a6e7061c6ac605849d102a39c6db392285992d07 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "win32.h"
 
-#include "global.h"
+#include "runtime.h"
 
 #include <wincrypt.h>
 #include <strsafe.h>
@@ -129,7 +129,8 @@ int git_hash_sha1_global_init(void)
        if ((error = hash_cng_prov_init()) < 0)
                error = hash_cryptoapi_prov_init();
 
-       git__on_shutdown(sha1_shutdown);
+       if (!error)
+               error = git_runtime_shutdown_register(sha1_shutdown);
 
        return error;
 }
@@ -163,7 +164,7 @@ GIT_INLINE(int) hash_cryptoapi_update(git_hash_sha1_ctx *ctx, const void *_data,
 {
        const BYTE *data = (BYTE *)_data;
 
-       assert(ctx->ctx.cryptoapi.valid);
+       GIT_ASSERT(ctx->ctx.cryptoapi.valid);
 
        while (len > 0) {
                DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len;
@@ -185,7 +186,7 @@ GIT_INLINE(int) hash_cryptoapi_final(git_oid *out, git_hash_sha1_ctx *ctx)
        DWORD len = 20;
        int error = 0;
 
-       assert(ctx->ctx.cryptoapi.valid);
+       GIT_ASSERT(ctx->ctx.cryptoapi.valid);
 
        if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out->id, &len, 0)) {
                git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished");
@@ -285,7 +286,7 @@ int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
 {
        int error = 0;
 
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        /*
         * When compiled with GIT_THREADS, the global hash_prov data is
@@ -302,27 +303,30 @@ int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
 
 int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
 {
-       assert(ctx && ctx->type);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(ctx->type);
        return (ctx->type == CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx);
 }
 
 int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
 {
-       assert(ctx && ctx->type);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(ctx->type);
        return (ctx->type == CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len);
 }
 
 int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
 {
-       assert(ctx && ctx->type);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(ctx->type);
        return (ctx->type == CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx);
 }
 
 void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
 {
-       assert(ctx);
-
-       if (ctx->type == CNG)
+       if (!ctx)
+               return;
+       else if (ctx->type == CNG)
                hash_ctx_cng_cleanup(ctx);
        else if(ctx->type == CRYPTOAPI)
                hash_ctx_cryptoapi_cleanup(ctx);
index 14ec34b2f01683744f6c012478da06f2d3d04a28..6b4fb835216bd9d5b6d73532f5383f4e45986c82 100644 (file)
@@ -17,7 +17,7 @@ typedef uint64_t hashsig_state;
 #define HASHSIG_SCALE 100
 
 #define HASHSIG_MAX_RUN 80
-#define HASHSIG_HASH_START     0x012345678ABCDEF0LL
+#define HASHSIG_HASH_START     INT64_C(0x012345678ABCDEF0)
 #define HASHSIG_HASH_SHIFT  5
 
 #define HASHSIG_HASH_MIX(S,CH) \
@@ -133,13 +133,13 @@ typedef struct {
        uint8_t ignore_ch[256];
 } hashsig_in_progress;
 
-static void hashsig_in_progress_init(
+static int hashsig_in_progress_init(
        hashsig_in_progress *prog, git_hashsig *sig)
 {
        int i;
 
        /* no more than one can be set */
-       assert(!(sig->opt & GIT_HASHSIG_IGNORE_WHITESPACE) ||
+       GIT_ASSERT(!(sig->opt & GIT_HASHSIG_IGNORE_WHITESPACE) ||
                   !(sig->opt & GIT_HASHSIG_SMART_WHITESPACE));
 
        if (sig->opt & GIT_HASHSIG_IGNORE_WHITESPACE) {
@@ -153,6 +153,8 @@ static void hashsig_in_progress_init(
        } else {
                memset(prog, 0, sizeof(*prog));
        }
+
+       return 0;
 }
 
 static int hashsig_add_hashes(
@@ -251,7 +253,8 @@ int git_hashsig_create(
        git_hashsig *sig = hashsig_alloc(opts);
        GIT_ERROR_CHECK_ALLOC(sig);
 
-       hashsig_in_progress_init(&prog, sig);
+       if ((error = hashsig_in_progress_init(&prog, sig)) < 0)
+               return error;
 
        error = hashsig_add_hashes(sig, (const uint8_t *)buf, buflen, &prog);
 
@@ -283,7 +286,10 @@ int git_hashsig_create_fromfile(
                return fd;
        }
 
-       hashsig_in_progress_init(&prog, sig);
+       if ((error = hashsig_in_progress_init(&prog, sig)) < 0) {
+               p_close(fd);
+               return error;
+       }
 
        while (!error) {
                if ((buflen = p_read(fd, buf, sizeof(buf))) <= 0) {
@@ -318,7 +324,7 @@ static int hashsig_heap_compare(const hashsig_heap *a, const hashsig_heap *b)
 {
        int matches = 0, i, j, cmp;
 
-       assert(a->cmp == b->cmp);
+       GIT_ASSERT_WITH_RETVAL(a->cmp == b->cmp, 0);
 
        /* hash heaps are sorted - just look for overlap vs total */
 
@@ -354,9 +360,16 @@ int git_hashsig_compare(const git_hashsig *a, const git_hashsig *b)
        /* if we have fewer than the maximum number of elements, then just use
         * one array since the two arrays will be the same
         */
-       if (a->mins.size < HASHSIG_HEAP_SIZE)
+       if (a->mins.size < HASHSIG_HEAP_SIZE) {
                return hashsig_heap_compare(&a->mins, &b->mins);
-       else
-               return (hashsig_heap_compare(&a->mins, &b->mins) +
-                               hashsig_heap_compare(&a->maxs, &b->maxs)) / 2;
+       } else {
+               int mins, maxs;
+
+               if ((mins = hashsig_heap_compare(&a->mins, &b->mins)) < 0)
+                       return mins;
+               if ((maxs = hashsig_heap_compare(&a->maxs, &b->maxs)) < 0)
+                       return maxs;
+
+               return (mins + maxs) / 2;
+       }
 }
index 7eccf9a4358eddf8c8e3c95e7c87006d954131d1..e5aab80ed1e35f944dcd9daab3b6aa12c5de1221 100644 (file)
@@ -10,7 +10,6 @@
 #include "git2/sys/filter.h"
 #include "filter.h"
 #include "buffer.h"
-#include "buf_text.h"
 
 static int ident_find_id(
        const char **id_start, const char **id_end, const char *start, size_t len)
@@ -105,7 +104,7 @@ static int ident_apply(
        GIT_UNUSED(self); GIT_UNUSED(payload);
 
        /* Don't filter binary files */
-       if (git_buf_text_is_binary(from))
+       if (git_buf_is_binary(from))
                return GIT_PASSTHROUGH;
 
        if (git_filter_source_mode(src) == GIT_FILTER_SMUDGE)
@@ -114,6 +113,17 @@ static int ident_apply(
                return ident_remove_id(to, from);
 }
 
+static int ident_stream(
+       git_writestream **out,
+       git_filter *self,
+       void **payload,
+       const git_filter_source *src,
+       git_writestream *next)
+{
+       return git_filter_buffered_stream_new(out,
+               self, ident_apply, NULL, payload, src, next);
+}
+
 git_filter *git_ident_filter_new(void)
 {
        git_filter *f = git__calloc(1, sizeof(git_filter));
@@ -123,7 +133,7 @@ git_filter *git_ident_filter_new(void)
        f->version = GIT_FILTER_VERSION;
        f->attributes = "+ident"; /* apply to files with ident attribute set */
        f->shutdown = git_filter_free;
-       f->apply    = ident_apply;
+       f->stream   = ident_stream;
 
        return f;
 }
index f5fb507e68f185e3d7a724ed804086fa1904af57..9ead96ba67ef46eaba4a4fbfdd12147e64e33290 100644 (file)
@@ -101,7 +101,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
  */
 static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
 {
-       int error = 0, wildmatch_flags;
+       int error = 0, wildmatch_flags, effective_flags;
        size_t i;
        git_attr_fnmatch *rule;
        char *path;
@@ -141,8 +141,17 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
                if (git_buf_oom(&buf))
                        goto out;
 
+               /*
+                * if rule isn't for full path we match without PATHNAME flag
+                * as lines like *.txt should match something like dir/test.txt
+                * requiring * to also match /
+                */
+               effective_flags = wildmatch_flags;
+               if (!(rule->flags & GIT_ATTR_FNMATCH_FULLPATH))
+                       effective_flags &= ~WM_PATHNAME;
+
                /* if we found a match, we want to keep this rule */
-               if ((wildmatch(git_buf_cstr(&buf), path, wildmatch_flags)) == WM_MATCH) {
+               if ((wildmatch(git_buf_cstr(&buf), path, effective_flags)) == WM_MATCH) {
                        *out = 1;
                        error = 0;
                        goto out;
@@ -238,11 +247,12 @@ static int push_ignore_file(
        const char *base,
        const char *filename)
 {
-       int error = 0;
+       git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE, base, filename };
        git_attr_file *file = NULL;
+       int error = 0;
+
+       error = git_attr_cache__get(&file, ignores->repo, NULL, &source, parse_ignore_file, false);
 
-       error = git_attr_cache__get(&file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
-                                   base, filename, parse_ignore_file, false);
        if (error < 0)
                return error;
 
@@ -263,13 +273,13 @@ static int push_one_ignore(void *payload, const char *path)
 
 static int get_internal_ignores(git_attr_file **out, git_repository *repo)
 {
+       git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_MEMORY, NULL, GIT_IGNORE_INTERNAL };
        int error;
 
        if ((error = git_attr_cache__init(repo)) < 0)
                return error;
 
-       error = git_attr_cache__get(out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL,
-                                   GIT_IGNORE_INTERNAL, NULL, false);
+       error = git_attr_cache__get(out, repo, NULL, &source, NULL, false);
 
        /* if internal rules list is empty, insert default rules */
        if (!error && !(*out)->rules.length)
@@ -287,7 +297,9 @@ int git_ignore__for_path(
        const char *workdir = git_repository_workdir(repo);
        git_buf infopath = GIT_BUF_INIT;
 
-       assert(repo && ignores && path);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(ignores);
+       GIT_ASSERT_ARG(path);
 
        memset(ignores, 0, sizeof(*ignores));
        ignores->repo = repo;
@@ -307,12 +319,17 @@ int git_ignore__for_path(
                if ((error = git_path_dirname_r(&local, path)) < 0 ||
                    (error = git_path_resolve_relative(&local, 0)) < 0 ||
                    (error = git_path_to_dir(&local)) < 0 ||
-                   (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0)
-               {;} /* Nothing, we just want to stop on the first error */
+                   (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0 ||
+                   (error = git_path_validate_workdir_buf(repo, &ignores->dir)) < 0) {
+                       /* Nothing, we just want to stop on the first error */
+               }
+
                git_buf_dispose(&local);
        } else {
-               error = git_buf_joinpath(&ignores->dir, path, "");
+               if (!(error = git_buf_joinpath(&ignores->dir, path, "")))
+                   error = git_path_validate_filesystem(ignores->dir.ptr, ignores->dir.size);
        }
+
        if (error < 0)
                goto cleanup;
 
@@ -521,7 +538,9 @@ int git_ignore_path_is_ignored(
        git_attr_file *file;
        git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
 
-       assert(repo && ignored && pathname);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(ignored);
+       GIT_ASSERT_ARG(pathname);
 
        workdir = git_repository_workdir(repo);
 
@@ -586,7 +605,7 @@ int git_ignore__check_pathspec_for_exact_ignores(
        git_attr_fnmatch *match;
        int ignored;
        git_buf path = GIT_BUF_INIT;
-       const char *wd, *filename;
+       const char *filename;
        git_index *idx;
 
        if ((error = git_repository__ensure_not_bare(
@@ -594,8 +613,6 @@ int git_ignore__check_pathspec_for_exact_ignores(
                (error = git_repository_index(&idx, repo)) < 0)
                return error;
 
-       wd = git_repository_workdir(repo);
-
        git_vector_foreach(vspec, i, match) {
                /* skip wildcard matches (if they are being used) */
                if ((match->flags & GIT_ATTR_FNMATCH_HASWILD) != 0 &&
@@ -608,7 +625,7 @@ int git_ignore__check_pathspec_for_exact_ignores(
                if (git_index_get_bypath(idx, filename, 0) != NULL)
                        continue;
 
-               if ((error = git_buf_joinpath(&path, wd, filename)) < 0)
+               if ((error = git_repository_workdir_path(&path, repo, filename)) < 0)
                        break;
 
                /* is there a file on disk that matches this exactly? */
@@ -632,4 +649,3 @@ int git_ignore__check_pathspec_for_exact_ignores(
 
        return error;
 }
-
index d5afc9bb695a2a9e7d7ffbbca03cad13154ce57a..5c3305170089424a2a4476a5eb11326d29e34726 100644 (file)
@@ -406,7 +406,7 @@ int git_index_open(git_index **index_out, const char *index_path)
        git_index *index;
        int error = -1;
 
-       assert(index_out);
+       GIT_ASSERT_ARG(index_out);
 
        index = git__calloc(1, sizeof(git_index));
        GIT_ERROR_CHECK_ALLOC(index);
@@ -461,7 +461,8 @@ static void index_free(git_index *index)
        /* index iterators increment the refcount of the index, so if we
         * get here then there should be no outstanding iterators.
         */
-       assert(!git_atomic_get(&index->readers));
+       if (git_atomic32_get(&index->readers))
+               return;
 
        git_index_clear(index);
        git_idxmap_free(index->entries_map);
@@ -487,14 +488,14 @@ void git_index_free(git_index *index)
 /* call with locked index */
 static void index_free_deleted(git_index *index)
 {
-       int readers = (int)git_atomic_get(&index->readers);
+       int readers = (int)git_atomic32_get(&index->readers);
        size_t i;
 
        if (readers > 0 || !index->deleted.length)
                return;
 
        for (i = 0; i < index->deleted.length; ++i) {
-               git_index_entry *ie = git__swap(index->deleted.contents[i], NULL);
+               git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL);
                index_entry_free(ie);
        }
 
@@ -515,7 +516,7 @@ static int index_remove_entry(git_index *index, size_t pos)
        error = git_vector_remove(&index->entries, pos);
 
        if (!error) {
-               if (git_atomic_get(&index->readers) > 0) {
+               if (git_atomic32_get(&index->readers) > 0) {
                        error = git_vector_insert(&index->deleted, entry);
                } else {
                        index_entry_free(entry);
@@ -531,7 +532,7 @@ int git_index_clear(git_index *index)
 {
        int error = 0;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        index->dirty = 1;
        index->tree = NULL;
@@ -566,7 +567,7 @@ int git_index_set_caps(git_index *index, int caps)
 {
        unsigned int old_ignore_case;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        old_ignore_case = index->ignore_case;
 
@@ -778,14 +779,14 @@ done:
 
 unsigned git_index_version(git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        return index->version;
 }
 
 int git_index_set_version(git_index *index, unsigned int version)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        if (version < INDEX_VERSION_NUMBER_LB ||
            version > INDEX_VERSION_NUMBER_UB) {
@@ -814,9 +815,9 @@ int git_index_write(git_index *index)
        return error;
 }
 
-const char * git_index_path(const git_index *index)
+const char *git_index_path(const git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
        return index->index_file_path;
 }
 
@@ -824,7 +825,8 @@ int git_index_write_tree(git_oid *oid, git_index *index)
 {
        git_repository *repo;
 
-       assert(oid && index);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(index);
 
        repo = INDEX_OWNER(index);
 
@@ -838,20 +840,25 @@ int git_index_write_tree(git_oid *oid, git_index *index)
 int git_index_write_tree_to(
        git_oid *oid, git_index *index, git_repository *repo)
 {
-       assert(oid && index && repo);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(repo);
+
        return git_tree__write_index(oid, index, repo);
 }
 
 size_t git_index_entrycount(const git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
+
        return index->entries.length;
 }
 
 const git_index_entry *git_index_get_byindex(
        git_index *index, size_t n)
 {
-       assert(index);
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
+
        git_vector_sort(&index->entries);
        return git_vector_get(&index->entries, n);
 }
@@ -862,7 +869,7 @@ const git_index_entry *git_index_get_bypath(
        git_index_entry key = {{ 0 }};
        git_index_entry *value;
 
-       assert(index);
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
 
        key.path = path;
        GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
@@ -937,7 +944,7 @@ static int index_entry_create(
        if (st)
                mode = st->st_mode;
 
-       if (!git_path_isvalid(repo, path, mode, path_valid_flags)) {
+       if (!git_path_validate(repo, path, mode, path_valid_flags)) {
                git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path);
                return -1;
        }
@@ -981,7 +988,7 @@ static int index_entry_init(
        if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
                return GIT_EBAREREPO;
 
-       if (git_buf_joinpath(&path, git_repository_workdir(repo), rel_path) < 0)
+       if (git_repository_workdir_path(&path, repo, rel_path) < 0)
                return -1;
 
        error = git_path_lstat(path.ptr, &st);
@@ -1039,23 +1046,24 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
 {
        git_index_reuc_entry *reuc = NULL;
 
-       assert(reuc_out && path);
+       GIT_ASSERT_ARG(reuc_out);
+       GIT_ASSERT_ARG(path);
 
        *reuc_out = reuc = reuc_entry_alloc(path);
        GIT_ERROR_CHECK_ALLOC(reuc);
 
        if ((reuc->mode[0] = ancestor_mode) > 0) {
-               assert(ancestor_oid);
+               GIT_ASSERT(ancestor_oid);
                git_oid_cpy(&reuc->oid[0], ancestor_oid);
        }
 
        if ((reuc->mode[1] = our_mode) > 0) {
-               assert(our_oid);
+               GIT_ASSERT(our_oid);
                git_oid_cpy(&reuc->oid[1], our_oid);
        }
 
        if ((reuc->mode[2] = their_mode) > 0) {
-               assert(their_oid);
+               GIT_ASSERT(their_oid);
                git_oid_cpy(&reuc->oid[2], their_oid);
        }
 
@@ -1347,7 +1355,8 @@ static int index_insert(
        size_t path_length, position;
        int error;
 
-       assert(index && entry_ptr);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(entry_ptr);
 
        entry = *entry_ptr;
 
@@ -1472,7 +1481,8 @@ int git_index_add_from_buffer(
        int error = 0;
        git_oid id;
 
-       assert(index && source_entry->path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(source_entry && source_entry->path);
 
        if (INDEX_OWNER(index) == NULL)
                return create_index_error(-1,
@@ -1522,7 +1532,7 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const
        struct stat st;
        int error;
 
-       if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
+       if ((error = git_repository_workdir_path(&abspath, repo, path)) < 0)
                return error;
 
        if ((error = p_stat(abspath.ptr, &st)) < 0) {
@@ -1557,7 +1567,8 @@ int git_index_add_bypath(git_index *index, const char *path)
        git_index_entry *entry = NULL;
        int ret;
 
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
 
        if ((ret = index_entry_init(&entry, index, path)) == 0)
                ret = index_insert(index, &entry, 1, false, false, true);
@@ -1609,7 +1620,8 @@ int git_index_remove_bypath(git_index *index, const char *path)
 {
        int ret;
 
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
 
        if (((ret = git_index_remove(index, path, 0)) < 0 &&
                ret != GIT_ENOTFOUND) ||
@@ -1629,7 +1641,7 @@ int git_index__fill(git_index *index, const git_vector *source_entries)
        int error = 0;
        size_t i;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        if (!source_entries->length)
                return 0;
@@ -1670,7 +1682,8 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
        git_index_entry *entry = NULL;
        int ret;
 
-       assert(index && source_entry && source_entry->path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(source_entry && source_entry->path);
 
        if (!valid_filemode(source_entry->mode)) {
                git_error_set(GIT_ERROR_INDEX, "invalid entry mode");
@@ -1758,7 +1771,8 @@ int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
 int git_index__find_pos(
        size_t *out, git_index *index, const char *path, size_t path_len, int stage)
 {
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
        return index_find(out, index, path, path_len, stage);
 }
 
@@ -1766,7 +1780,8 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
 {
        size_t pos;
 
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
 
        if (git_vector_bsearch2(
                        &pos, &index->entries, index->entries_search_path, path) < 0) {
@@ -1799,7 +1814,7 @@ int git_index_conflict_add(git_index *index,
        unsigned short i;
        int ret = 0;
 
-       assert (index);
+       GIT_ASSERT_ARG(index);
 
        if ((ancestor_entry &&
                        (ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) ||
@@ -1870,7 +1885,10 @@ static int index_conflict__get_byindex(
        size_t count;
        int stage, len = 0;
 
-       assert(ancestor_out && our_out && their_out && index);
+       GIT_ASSERT_ARG(ancestor_out);
+       GIT_ASSERT_ARG(our_out);
+       GIT_ASSERT_ARG(their_out);
+       GIT_ASSERT_ARG(index);
 
        *ancestor_out = NULL;
        *our_out = NULL;
@@ -1916,7 +1934,11 @@ int git_index_conflict_get(
        size_t pos;
        int len = 0;
 
-       assert(ancestor_out && our_out && their_out && index && path);
+       GIT_ASSERT_ARG(ancestor_out);
+       GIT_ASSERT_ARG(our_out);
+       GIT_ASSERT_ARG(their_out);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
 
        *ancestor_out = NULL;
        *our_out = NULL;
@@ -1963,13 +1985,14 @@ static int index_conflict_remove(git_index *index, const char *path)
 
 int git_index_conflict_remove(git_index *index, const char *path)
 {
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
        return index_conflict_remove(index, path);
 }
 
 int git_index_conflict_cleanup(git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
        return index_conflict_remove(index, NULL);
 }
 
@@ -1978,7 +2001,7 @@ int git_index_has_conflicts(const git_index *index)
        size_t i;
        git_index_entry *entry;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        git_vector_foreach(&index->entries, i, entry) {
                if (GIT_INDEX_ENTRY_STAGE(entry) > 0)
@@ -1995,7 +2018,8 @@ int git_index_iterator_new(
        git_index_iterator *it;
        int error;
 
-       assert(iterator_out && index);
+       GIT_ASSERT_ARG(iterator_out);
+       GIT_ASSERT_ARG(index);
 
        it = git__calloc(1, sizeof(git_index_iterator));
        GIT_ERROR_CHECK_ALLOC(it);
@@ -2015,7 +2039,8 @@ int git_index_iterator_next(
        const git_index_entry **out,
        git_index_iterator *it)
 {
-       assert(out && it);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(it);
 
        if (it->cur >= git_vector_length(&it->snap))
                return GIT_ITEROVER;
@@ -2039,7 +2064,8 @@ int git_index_conflict_iterator_new(
 {
        git_index_conflict_iterator *it = NULL;
 
-       assert(iterator_out && index);
+       GIT_ASSERT_ARG(iterator_out);
+       GIT_ASSERT_ARG(index);
 
        it = git__calloc(1, sizeof(git_index_conflict_iterator));
        GIT_ERROR_CHECK_ALLOC(it);
@@ -2059,7 +2085,10 @@ int git_index_conflict_next(
        const git_index_entry *entry;
        int len;
 
-       assert(ancestor_out && our_out && their_out && iterator);
+       GIT_ASSERT_ARG(ancestor_out);
+       GIT_ASSERT_ARG(our_out);
+       GIT_ASSERT_ARG(their_out);
+       GIT_ASSERT_ARG(iterator);
 
        *ancestor_out = NULL;
        *our_out = NULL;
@@ -2097,14 +2126,14 @@ void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
 
 size_t git_index_name_entrycount(git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
        return index->names.length;
 }
 
 const git_index_name_entry *git_index_name_get_byindex(
        git_index *index, size_t n)
 {
-       assert(index);
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
 
        git_vector_sort(&index->names);
        return git_vector_get(&index->names, n);
@@ -2125,7 +2154,7 @@ int git_index_name_add(git_index *index,
 {
        git_index_name_entry *conflict_name;
 
-       assert((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
+       GIT_ASSERT_ARG((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
 
        conflict_name = git__calloc(1, sizeof(git_index_name_entry));
        GIT_ERROR_CHECK_ALLOC(conflict_name);
@@ -2148,7 +2177,7 @@ int git_index_name_clear(git_index *index)
        size_t i;
        git_index_name_entry *conflict_name;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        git_vector_foreach(&index->names, i, conflict_name)
                index_name_entry_free(conflict_name);
@@ -2162,7 +2191,7 @@ int git_index_name_clear(git_index *index)
 
 size_t git_index_reuc_entrycount(git_index *index)
 {
-       assert(index);
+       GIT_ASSERT_ARG(index);
        return index->reuc.length;
 }
 
@@ -2179,8 +2208,9 @@ static int index_reuc_insert(
 {
        int res;
 
-       assert(index && reuc && reuc->path != NULL);
-       assert(git_vector_is_sorted(&index->reuc));
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(reuc && reuc->path != NULL);
+       GIT_ASSERT(git_vector_is_sorted(&index->reuc));
 
        res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
        index->dirty = 1;
@@ -2196,7 +2226,8 @@ int git_index_reuc_add(git_index *index, const char *path,
        git_index_reuc_entry *reuc = NULL;
        int error = 0;
 
-       assert(index && path);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(path);
 
        if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
                        ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
@@ -2215,12 +2246,14 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
        git_index *index, const char *path)
 {
        size_t pos;
-       assert(index && path);
+
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(path, NULL);
 
        if (!index->reuc.length)
                return NULL;
 
-       assert(git_vector_is_sorted(&index->reuc));
+       GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
 
        if (git_index_reuc_find(&pos, index, path) < 0)
                return NULL;
@@ -2231,8 +2264,8 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
 const git_index_reuc_entry *git_index_reuc_get_byindex(
        git_index *index, size_t n)
 {
-       assert(index);
-       assert(git_vector_is_sorted(&index->reuc));
+       GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
+       GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
 
        return git_vector_get(&index->reuc, n);
 }
@@ -2242,7 +2275,8 @@ int git_index_reuc_remove(git_index *index, size_t position)
        int error;
        git_index_reuc_entry *reuc;
 
-       assert(git_vector_is_sorted(&index->reuc));
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT(git_vector_is_sorted(&index->reuc));
 
        reuc = git_vector_get(&index->reuc, position);
        error = git_vector_remove(&index->reuc, position);
@@ -2258,10 +2292,10 @@ int git_index_reuc_clear(git_index *index)
 {
        size_t i;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        for (i = 0; i < index->reuc.length; ++i)
-               index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL));
+               index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL));
 
        git_vector_clear(&index->reuc);
 
@@ -2626,7 +2660,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
 
        seek_forward(INDEX_HEADER_SIZE);
 
-       assert(!index->entries.length);
+       GIT_ASSERT(!index->entries.length);
 
        if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0)
                return error;
@@ -2799,7 +2833,8 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha
        if (last) {
                varint_len = git_encode_varint((unsigned char *) path,
                                          disk_size, strlen(last) - same_len);
-               assert(varint_len > 0);
+               GIT_ASSERT(varint_len > 0);
+
                path += varint_len;
                disk_size -= varint_len;
 
@@ -2807,14 +2842,14 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha
                 * If using path compression, we are not allowed
                 * to have additional trailing NULs.
                 */
-               assert(disk_size == path_len + 1);
+               GIT_ASSERT(disk_size == path_len + 1);
        } else {
                /*
                 * If no path compression is used, we do have
                 * NULs as padding. As such, simply assert that
                 * we have enough space left to write the path.
                 */
-               assert(disk_size > path_len);
+               GIT_ASSERT(disk_size > path_len);
        }
 
        memcpy(path, path_start, path_len + 1);
@@ -2826,14 +2861,16 @@ static int write_entries(git_index *index, git_filebuf *file)
 {
        int error = 0;
        size_t i;
-       git_vector case_sorted, *entries;
+       git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL;
        git_index_entry *entry;
        const char *last = NULL;
 
        /* If index->entries is sorted case-insensitively, then we need
         * to re-sort it case-sensitively before writing */
        if (index->ignore_case) {
-               git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp);
+               if ((error = git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp)) < 0)
+                       goto done;
+
                git_vector_sort(&case_sorted);
                entries = &case_sorted;
        } else {
@@ -2850,9 +2887,8 @@ static int write_entries(git_index *index, git_filebuf *file)
                        last = entry->path;
        }
 
-       if (index->ignore_case)
-               git_vector_free(&case_sorted);
-
+done:
+       git_vector_free(&case_sorted);
        return error;
 }
 
@@ -3010,7 +3046,8 @@ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
        bool is_extended;
        uint32_t index_version_number;
 
-       assert(index && file);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(file);
 
        if (index->version <= INDEX_VERSION_NUMBER_EXT)  {
                is_extended = is_index_extended(index);
@@ -3161,7 +3198,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
                /* well, this isn't good */;
        } else {
                git_vector_swap(&entries, &index->entries);
-               entries_map = git__swap(index->entries_map, entries_map);
+               entries_map = git_atomic_swap(index->entries_map, entries_map);
        }
 
        index->dirty = 1;
@@ -3192,7 +3229,7 @@ static int git_index_read_iterator(
        size_t i;
        int error;
 
-       assert((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
+       GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
 
        if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
            (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
@@ -3295,7 +3332,7 @@ static int git_index_read_iterator(
            goto done;
 
        git_vector_swap(&new_entries, &index->entries);
-       new_entries_map = git__swap(index->entries_map, new_entries_map);
+       new_entries_map = git_atomic_swap(index->entries_map, new_entries_map);
 
        git_vector_foreach(&remove_entries, i, entry) {
                if (index->tree)
@@ -3364,7 +3401,7 @@ int git_index_add_all(
        git_pathspec ps;
        bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        repo = INDEX_OWNER(index);
        if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
@@ -3450,8 +3487,8 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr
                payload,
        };
 
-       assert(index);
-       assert(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
 
        repo = INDEX_OWNER(index);
 
@@ -3505,7 +3542,7 @@ static int index_apply_to_all(
        const char *match;
        git_buf path = GIT_BUF_INIT;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        if ((error = git_pathspec__init(&ps, paths)) < 0)
                return error;
@@ -3601,7 +3638,7 @@ int git_index_snapshot_new(git_vector *snap, git_index *index)
 
        GIT_REFCOUNT_INC(index);
 
-       git_atomic_inc(&index->readers);
+       git_atomic32_inc(&index->readers);
        git_vector_sort(&index->entries);
 
        error = git_vector_dup(snap, &index->entries, index->entries._cmp);
@@ -3616,7 +3653,7 @@ void git_index_snapshot_release(git_vector *snap, git_index *index)
 {
        git_vector_free(snap);
 
-       git_atomic_dec(&index->readers);
+       git_atomic32_dec(&index->readers);
 
        git_index_free(index);
 }
index 54402f5634bccf4a08f63c5bae8493488a54e134..a365867d0bf6cb9dbc8c148d1cef259dc9cac213 100644 (file)
@@ -33,7 +33,7 @@ struct git_index {
        git_idxmap *entries_map;
 
        git_vector deleted; /* deleted entries if readers > 0 */
-       git_atomic readers; /* number of active iterators */
+       git_atomic32 readers; /* number of active iterators */
 
        unsigned int on_disk:1;
        unsigned int ignore_case:1;
index 8c74f0e72cfd4aa001264d23c58830bf7ceccadb..ce77375007c75909227c6d5de27e6c0e2fece199 100644 (file)
@@ -24,8 +24,6 @@
 #include "zstream.h"
 #include "object.h"
 
-extern git_mutex git__mwindow_mutex;
-
 size_t git_indexer__max_objects = UINT32_MAX;
 
 #define UINT31_MAX (0x7FFFFFFF)
@@ -239,7 +237,8 @@ static int hash_object_stream(git_indexer*idx, git_packfile_stream *stream)
 {
        ssize_t read;
 
-       assert(idx && stream);
+       GIT_ASSERT_ARG(idx);
+       GIT_ASSERT_ARG(stream);
 
        do {
                if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0)
@@ -262,7 +261,7 @@ static int advance_delta_offset(git_indexer *idx, git_object_t type)
 {
        git_mwindow *w = NULL;
 
-       assert(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA);
+       GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA);
 
        if (type == GIT_OBJECT_REF_DELTA) {
                idx->off += GIT_OID_RAWSZ;
@@ -282,7 +281,7 @@ static int read_object_stream(git_indexer *idx, git_packfile_stream *stream)
 {
        ssize_t read;
 
-       assert(stream);
+       GIT_ASSERT_ARG(stream);
 
        do {
                read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf));
@@ -602,6 +601,48 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
        idx->inbuf_len += size - to_expell;
 }
 
+#if defined(NO_MMAP) || !defined(GIT_WIN32)
+
+static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
+{
+       size_t remaining_size = size;
+       const char *ptr = (const char *)data;
+
+       /* Handle data size larger that ssize_t */
+       while (remaining_size > 0) {
+               ssize_t nb;
+               HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr,
+                                         remaining_size, offset));
+               if (nb <= 0)
+                       return -1;
+
+               ptr += nb;
+               offset += nb;
+               remaining_size -= nb;
+       }
+
+       return 0;
+}
+
+static int append_to_pack(git_indexer *idx, const void *data, size_t size)
+{
+       if (write_at(idx, data, idx->pack->mwf.size, size) < 0) {
+               git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
+               return -1;
+       }
+
+       return 0;
+}
+
+#else
+
+/*
+ * Windows may keep different views to a networked file for the mmap- and
+ * open-accessed versions of a file, so any writes done through
+ * `write(2)`/`pwrite(2)` may not be reflected on the data that `mmap(2)` is
+ * able to read.
+ */
+
 static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
 {
        git_file fd = idx->pack->mwf.fd;
@@ -612,7 +653,8 @@ static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t s
        git_map map;
        int error;
 
-       assert(data && size);
+       GIT_ASSERT_ARG(data);
+       GIT_ASSERT_ARG(size);
 
        if ((error = git__mmap_alignment(&mmap_alignment)) < 0)
                return error;
@@ -638,7 +680,6 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size)
        size_t page_offset;
        off64_t page_start;
        off64_t current_size = idx->pack->mwf.size;
-       int fd = idx->pack->mwf.fd;
        int error;
 
        if (!size)
@@ -655,8 +696,7 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size)
        page_offset = new_size % mmap_alignment;
        page_start = new_size - page_offset;
 
-       if (p_lseek(fd, page_start + mmap_alignment - 1, SEEK_SET) < 0 ||
-           p_write(idx->pack->mwf.fd, data, 1) < 0) {
+       if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) {
                git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
                return -1;
        }
@@ -664,6 +704,8 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size)
        return write_at(idx, data, idx->pack->mwf.size, size);
 }
 
+#endif
+
 static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
 {
        git_packfile_stream *stream = &idx->stream;
@@ -677,7 +719,7 @@ static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
                return GIT_EBUFS;
 
        if (!idx->have_stream) {
-               error = git_packfile_unpack_header(&entry_size, &type, &idx->pack->mwf, &w, &idx->off);
+               error = git_packfile_unpack_header(&entry_size, &type, idx->pack, &w, &idx->off);
                if (error == GIT_EBUFS) {
                        idx->off = entry_start;
                        return error;
@@ -759,7 +801,9 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_inde
        struct git_pack_header *hdr = &idx->hdr;
        git_mwindow_file *mwf = &idx->pack->mwf;
 
-       assert(idx && data && stats);
+       GIT_ASSERT_ARG(idx);
+       GIT_ASSERT_ARG(data);
+       GIT_ASSERT_ARG(stats);
 
        if ((error = append_to_pack(idx, data, size)) < 0)
                return error;
@@ -813,7 +857,8 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_inde
        /* Now that we have data in the pack, let's try to parse it */
 
        /* As the file grows any windows we try to use will be out of date */
-       git_mwindow_free_all(mwf);
+       if ((error = git_mwindow_free_all(mwf)) < 0)
+               goto on_error;
 
        while (stats->indexed_objects < idx->nr_objects) {
                if ((error = read_stream_object(idx, stats)) != 0) {
@@ -857,16 +902,16 @@ static int index_path(git_buf *path, git_indexer *idx, const char *suffix)
  * Rewind the packfile by the trailer, as we might need to fix the
  * packfile by injecting objects at the tail and must overwrite it.
  */
-static void seek_back_trailer(git_indexer *idx)
+static int seek_back_trailer(git_indexer *idx)
 {
        idx->pack->mwf.size -= GIT_OID_RAWSZ;
-       git_mwindow_free_all(&idx->pack->mwf);
+       return git_mwindow_free_all(&idx->pack->mwf);
 }
 
 static int inject_object(git_indexer *idx, git_oid *id)
 {
-       git_odb_object *obj;
-       struct entry *entry;
+       git_odb_object *obj = NULL;
+       struct entry *entry = NULL;
        struct git_pack_entry *pentry = NULL;
        git_oid foo = {{0}};
        unsigned char hdr[64];
@@ -876,12 +921,14 @@ static int inject_object(git_indexer *idx, git_oid *id)
        size_t len, hdr_len;
        int error;
 
-       seek_back_trailer(idx);
+       if ((error = seek_back_trailer(idx)) < 0)
+               goto cleanup;
+
        entry_start = idx->pack->mwf.size;
 
-       if (git_odb_read(&obj, idx->odb, id) < 0) {
+       if ((error = git_odb_read(&obj, idx->odb, id)) < 0) {
                git_error_set(GIT_ERROR_INDEXER, "missing delta bases");
-               return -1;
+               goto cleanup;
        }
 
        data = git_odb_object_data(obj);
@@ -893,8 +940,8 @@ static int inject_object(git_indexer *idx, git_oid *id)
        entry->crc = crc32(0L, Z_NULL, 0);
 
        /* Write out the object header */
-       hdr_len = git_packfile__object_header(hdr, len, git_odb_object_type(obj));
-       if ((error = append_to_pack(idx, hdr, hdr_len)) < 0)
+       if ((error = git_packfile__object_header(&hdr_len, hdr, len, git_odb_object_type(obj))) < 0 ||
+           (error = append_to_pack(idx, hdr, hdr_len)) < 0)
                goto cleanup;
 
        idx->pack->mwf.size += hdr_len;
@@ -950,7 +997,7 @@ static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats)
        unsigned int left = 0;
        git_oid base;
 
-       assert(git_vector_length(&idx->deltas) > 0);
+       GIT_ASSERT(git_vector_length(&idx->deltas) > 0);
 
        if (idx->odb == NULL) {
                git_error_set(GIT_ERROR_INDEXER, "cannot fix a thin pack without an ODB");
@@ -963,7 +1010,7 @@ static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats)
                        continue;
 
                curpos = delta->delta_off;
-               error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos);
+               error = git_packfile_unpack_header(&size, &type, idx->pack, &w, &curpos);
                if (error < 0)
                        return error;
 
@@ -1081,7 +1128,9 @@ static int update_header_and_rehash(git_indexer *idx, git_indexer_progress *stat
         * hash_partially() keep the existing trailer out of the
         * calculation.
         */
-       git_mwindow_free_all(mwf);
+       if (git_mwindow_free_all(mwf) < 0)
+               return -1;
+
        idx->inbuf_len = 0;
        while (hashed < mwf->size) {
                ptr = git_mwindow_open(mwf, &w, hashed, chunk, &left);
@@ -1253,13 +1302,22 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
        if (git_filebuf_commit_at(&index_file, filename.ptr) < 0)
                goto on_error;
 
-       git_mwindow_free_all(&idx->pack->mwf);
+       if (git_mwindow_free_all(&idx->pack->mwf) < 0)
+               goto on_error;
 
-       /* Truncate file to undo rounding up to next page_size in append_to_pack */
+#if !defined(NO_MMAP) && defined(GIT_WIN32)
+       /*
+        * Some non-Windows remote filesystems fail when truncating files if the
+        * file permissions change after opening the file (done by p_mkstemp).
+        *
+        * Truncation is only needed when mmap is used to undo rounding up to next
+        * page_size in append_to_pack.
+        */
        if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name);
                return -1;
        }
+#endif
 
        if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to fsync packfile");
@@ -1323,13 +1381,7 @@ void git_indexer_free(git_indexer *idx)
 
        git_vector_free_deep(&idx->deltas);
 
-       if (!git_mutex_lock(&git__mwindow_mutex)) {
-               if (!idx->pack_committed)
-                       git_packfile_close(idx->pack, true);
-
-               git_packfile_free(idx->pack);
-               git_mutex_unlock(&git__mwindow_mutex);
-       }
+       git_packfile_free(idx->pack, !idx->pack_committed);
 
        iter = 0;
        while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0)
index 067c0be1fcde7eedb314a10bc2d7c8c6bd0ba9bd..63277177bf34c69b2e7b91fd80a882dd83d49f91 100644 (file)
@@ -43,10 +43,10 @@ GIT_INLINE(int) git__is_ulong(int64_t p)
 }
 
 /** @return true if p fits into the range of an int */
-GIT_INLINE(int) git__is_int(long long p)
+GIT_INLINE(int) git__is_int(int64_t p)
 {
        int r = (int)p;
-       return p == (long long)r;
+       return p == (int64_t)r;
 }
 
 /* Use clang/gcc compiler intrinsics whenever possible */
@@ -77,6 +77,15 @@ GIT_INLINE(int) git__is_int(long long p)
 # define git__sub_int_overflow(out, one, two) \
     __builtin_ssub_overflow(one, two, out)
 
+# define git__add_int64_overflow(out, one, two) \
+    __builtin_add_overflow(one, two, out)
+
+/* clang on 32-bit systems produces an undefined reference to `__mulodi4`. */
+# if !defined(__clang__) || !defined(GIT_ARCH_32)
+#  define git__multiply_int64_overflow(out, one, two) \
+     __builtin_mul_overflow(one, two, out)
+# endif
+
 /* Use Microsoft's safe integer handling functions where available */
 #elif defined(_MSC_VER)
 
@@ -87,11 +96,17 @@ GIT_INLINE(int) git__is_int(long long p)
     (SizeTAdd(one, two, out) != S_OK)
 # define git__multiply_sizet_overflow(out, one, two) \
     (SizeTMult(one, two, out) != S_OK)
+
 #define git__add_int_overflow(out, one, two) \
     (IntAdd(one, two, out) != S_OK)
 #define git__sub_int_overflow(out, one, two) \
     (IntSub(one, two, out) != S_OK)
 
+#define git__add_int64_overflow(out, one, two) \
+    (LongLongAdd(one, two, out) != S_OK)
+#define git__multiply_int64_overflow(out, one, two) \
+    (LongLongMult(one, two, out) != S_OK)
+
 #else
 
 /**
@@ -136,6 +151,68 @@ GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
        return false;
 }
 
+GIT_INLINE(bool) git__add_int64_overflow(int64_t *out, int64_t one, int64_t two)
+{
+       if ((two > 0 && one > (INT64_MAX - two)) ||
+           (two < 0 && one < (INT64_MIN - two)))
+               return true;
+       *out = one + two;
+       return false;
+}
+
+#endif
+
+/* If we could not provide an intrinsic implementation for this, provide a (slow) fallback. */
+#if !defined(git__multiply_int64_overflow)
+GIT_INLINE(bool) git__multiply_int64_overflow(int64_t *out, int64_t one, int64_t two)
+{
+       /*
+        * Detects whether `INT64_MAX < (one * two) || INT64_MIN > (one * two)`,
+        * without incurring in undefined behavior. That is done by performing the
+        * comparison with a division instead of a multiplication, which translates
+        * to `INT64_MAX / one < two || INT64_MIN / one > two`. Some caveats:
+        *
+        * - The comparison sign is inverted when both sides of the inequality are
+        *   multiplied/divided by a negative number, so if `one < 0` the comparison
+        *   needs to be flipped.
+        * - `INT64_MAX / -1` itself overflows (or traps), so that case should be
+        *   avoided.
+        * - Since the overflow flag is defined as the discrepance between the result
+        *   of performing the multiplication in a signed integer at twice the width
+        *   of the operands, and the truncated+sign-extended version of that same
+        *   result, there are four cases where the result is the opposite of what
+        *   would be expected:
+        *   * `INT64_MIN * -1` / `-1 * INT64_MIN`
+        *   * `INT64_MIN * 1 / `1 * INT64_MIN`
+        */
+       if (one && two) {
+               if (one > 0 && two > 0) {
+                       if (INT64_MAX / one < two)
+                               return true;
+               } else if (one < 0 && two < 0) {
+                       if ((one == -1 && two == INT64_MIN) ||
+                                 (two == -1 && one == INT64_MIN)) {
+                               *out = INT64_MIN;
+                               return false;
+                       }
+                       if (INT64_MAX / one > two)
+                               return true;
+               } else if (one > 0 && two < 0) {
+                       if ((one == 1 && two == INT64_MIN) ||
+                           (INT64_MIN / one > two))
+                               return true;
+               } else if (one == -1) {
+                       if (INT64_MIN / two > one)
+                               return true;
+               } else {
+                       if ((one == INT64_MIN && two == 1) ||
+                           (INT64_MIN / one < two))
+                               return true;
+               }
+       }
+       *out = one * two;
+       return false;
+}
 #endif
 
 #endif
index a393187c07e658b733e8e54e239d48cd4c77c7e2..ce9f305ef28c7519b6c5447f58c28d2eeeef2da4 100644 (file)
@@ -330,7 +330,7 @@ static iterator_pathlist_search_t iterator_pathlist_search(
                        break;
 
                /* an exact match would have been matched by the bsearch above */
-               assert(p[path_len]);
+               GIT_ASSERT_WITH_RETVAL(p[path_len], ITERATOR_PATHLIST_NONE);
 
                /* is this a literal directory entry (eg `foo/`) or a file beneath */
                if (p[path_len] == '/') {
@@ -678,14 +678,14 @@ done:
        return error;
 }
 
-static void tree_iterator_frame_pop(tree_iterator *iter)
+static int tree_iterator_frame_pop(tree_iterator *iter)
 {
        tree_iterator_frame *frame;
        git_buf *buf = NULL;
        git_tree *tree;
        size_t i;
 
-       assert(iter->frames.size);
+       GIT_ASSERT(iter->frames.size);
 
        frame = git_array_pop(iter->frames);
 
@@ -705,6 +705,8 @@ static void tree_iterator_frame_pop(tree_iterator *iter)
        git_vector_free(&frame->similar_trees);
 
        git_buf_dispose(&frame->path);
+
+       return 0;
 }
 
 static int tree_iterator_current(
@@ -760,7 +762,9 @@ static int tree_iterator_advance(const git_index_entry **out, git_iterator *i)
 
                /* no more entries in this frame.  pop the frame out */
                if (frame->next_idx == frame->entries.length) {
-                       tree_iterator_frame_pop(iter);
+                       if ((error = tree_iterator_frame_pop(iter)) < 0)
+                               break;
+
                        continue;
                }
 
@@ -838,7 +842,7 @@ static int tree_iterator_advance_into(
        const git_index_entry **out, git_iterator *i)
 {
        tree_iterator *iter = (tree_iterator *)i;
-    tree_iterator_frame *frame;
+       tree_iterator_frame *frame;
        tree_iterator_entry *prev_entry;
        int error;
 
@@ -855,7 +859,7 @@ static int tree_iterator_advance_into(
         * we will have pushed a new (empty) frame on to the stack for this
         * new directory.  since it's empty, its current_entry should be null.
         */
-       assert(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
+       GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
 
        if (prev_entry) {
                if (!git_tree_entry__is_tree(prev_entry->tree_entry))
@@ -973,7 +977,7 @@ int git_iterator_current_tree_entry(
        tree_iterator_frame *frame;
        tree_iterator_entry *entry;
 
-       assert(i->type == GIT_ITERATOR_TREE);
+       GIT_ASSERT(i->type == GIT_ITERATOR_TREE);
 
        iter = (tree_iterator *)i;
 
@@ -990,11 +994,11 @@ int git_iterator_current_parent_tree(
        tree_iterator *iter;
        tree_iterator_frame *frame;
 
-       assert(i->type == GIT_ITERATOR_TREE);
+       GIT_ASSERT(i->type == GIT_ITERATOR_TREE);
 
        iter = (tree_iterator *)i;
 
-       assert(depth < iter->frames.size);
+       GIT_ASSERT(depth < iter->frames.size);
        frame = &iter->frames.ptr[iter->frames.size-depth-1];
 
        *parent_tree = frame->tree;
@@ -1274,7 +1278,8 @@ static int filesystem_iterator_entry_hash(
                return git_repository_hashfile(&entry->id,
                        iter->base.repo, entry->path, GIT_OBJECT_BLOB, NULL);
 
-       if (!(error = git_buf_joinpath(&fullpath, iter->root, entry->path)))
+       if (!(error = git_buf_joinpath(&fullpath, iter->root, entry->path)) &&
+           !(error = git_path_validate_workdir_buf(iter->base.repo, &fullpath)))
                error = git_odb_hashfile(&entry->id, fullpath.ptr, GIT_OBJECT_BLOB);
 
        git_buf_dispose(&fullpath);
@@ -1355,7 +1360,8 @@ static int filesystem_iterator_frame_push(
        else
                git_buf_puts(&root, iter->root);
 
-       if (git_buf_oom(&root)) {
+       if (git_buf_oom(&root) ||
+           git_path_validate_workdir_buf(iter->base.repo, &root) < 0) {
                error = -1;
                goto done;
        }
@@ -1385,10 +1391,11 @@ static int filesystem_iterator_frame_push(
                iterator_pathlist_search_t pathlist_match = ITERATOR_PATHLIST_FULL;
                bool dir_expected = false;
 
-               if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
+               if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0 ||
+                   (error = git_path_validate_workdir_with_len(iter->base.repo, path, path_len)) < 0)
                        goto done;
 
-               assert(path_len > iter->root_len);
+               GIT_ASSERT(path_len > iter->root_len);
 
                /* remove the prefix if requested */
                path += iter->root_len;
@@ -1469,17 +1476,19 @@ done:
        return error;
 }
 
-GIT_INLINE(void) filesystem_iterator_frame_pop(filesystem_iterator *iter)
+GIT_INLINE(int) filesystem_iterator_frame_pop(filesystem_iterator *iter)
 {
        filesystem_iterator_frame *frame;
 
-       assert(iter->frames.size);
+       GIT_ASSERT(iter->frames.size);
 
        frame = git_array_pop(iter->frames);
        filesystem_iterator_frame_pop_ignores(iter);
 
        git_pool_clear(&frame->entry_pool);
        git_vector_free(&frame->entries);
+
+       return 0;
 }
 
 static void filesystem_iterator_set_current(
@@ -1556,7 +1565,8 @@ static int filesystem_iterator_is_dir(
        }
 
        if ((error = git_buf_joinpath(&fullpath, iter->root, entry->path)) < 0 ||
-               (error = p_stat(fullpath.ptr, &st)) < 0)
+           (error = git_path_validate_workdir_buf(iter->base.repo, &fullpath)) < 0 ||
+           (error = p_stat(fullpath.ptr, &st)) < 0)
                goto done;
 
        *is_dir = S_ISDIR(st.st_mode);
@@ -1646,7 +1656,7 @@ static int filesystem_iterator_advance_into(
         * we will have pushed a new (empty) frame on to the stack for this
         * new directory.  since it's empty, its current_entry should be null.
         */
-       assert(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
+       GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
 
        if (prev_entry) {
                if (prev_entry->st.st_mode != GIT_FILEMODE_COMMIT &&
@@ -1762,12 +1772,13 @@ static int filesystem_iterator_advance_over(
        *out = NULL;
        *status = GIT_ITERATOR_STATUS_NORMAL;
 
-       assert(iterator__has_been_accessed(i));
+       GIT_ASSERT(iterator__has_been_accessed(i));
 
        current_frame = filesystem_iterator_current_frame(iter);
-       assert(current_frame);
+       GIT_ASSERT(current_frame);
+
        current_entry = filesystem_iterator_current_entry(current_frame);
-       assert(current_entry);
+       GIT_ASSERT(current_entry);
 
        if ((error = git_iterator_current(&entry, i)) < 0)
                return error;
@@ -2065,8 +2076,8 @@ static bool index_iterator_create_pseudotree(
 
 static int index_iterator_skip_pseudotree(index_iterator *iter)
 {
-       assert(iterator__has_been_accessed(&iter->base));
-       assert(S_ISDIR(iter->entry->mode));
+       GIT_ASSERT(iterator__has_been_accessed(&iter->base));
+       GIT_ASSERT(S_ISDIR(iter->entry->mode));
 
        while (true) {
                const git_index_entry *next_entry = NULL;
@@ -2280,10 +2291,11 @@ int git_iterator_reset_range(
        return i->cb->reset(i);
 }
 
-void git_iterator_set_ignore_case(git_iterator *i, bool ignore_case)
+int git_iterator_set_ignore_case(git_iterator *i, bool ignore_case)
 {
-       assert(!iterator__has_been_accessed(i));
+       GIT_ASSERT(!iterator__has_been_accessed(i));
        iterator_set_ignore_case(i, ignore_case);
+       return 0;
 }
 
 void git_iterator_free(git_iterator *iter)
index ebd69362bcca6f05c8012983443ac3df9b4f1c62..30465df2f033ded1ece4b82cd2655d60eb312402 100644 (file)
@@ -263,7 +263,7 @@ GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter)
        return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0);
 }
 
-extern void git_iterator_set_ignore_case(
+extern int git_iterator_set_ignore_case(
        git_iterator *iter, bool ignore_case);
 
 extern int git_iterator_current_tree_entry(
index 40e2d1848b77cfc10a10f84a66551e1d7e4e3d5d..7adccdb00652b642182e83e4c0894085cdd1565e 100644 (file)
@@ -131,17 +131,8 @@ int main() {
 
 /* compiler specific configuration */
 
-#if UINT_MAX == 0xffffffffu
-typedef unsigned int khint32_t;
-#elif ULONG_MAX == 0xffffffffu
-typedef unsigned long khint32_t;
-#endif
-
-#if ULONG_MAX == ULLONG_MAX
-typedef unsigned long khint64_t;
-#else
-typedef unsigned long long khint64_t;
-#endif
+typedef uint32_t khint32_t;
+typedef uint64_t khint64_t;
 
 #ifndef kh_inline
 #ifdef _MSC_VER
diff --git a/src/libgit2.c b/src/libgit2.c
new file mode 100644 (file)
index 0000000..cc793b4
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "libgit2.h"
+
+#include <git2.h>
+#include "alloc.h"
+#include "cache.h"
+#include "common.h"
+#include "filter.h"
+#include "hash.h"
+#include "index.h"
+#include "merge_driver.h"
+#include "pool.h"
+#include "mwindow.h"
+#include "object.h"
+#include "odb.h"
+#include "refs.h"
+#include "runtime.h"
+#include "sysdir.h"
+#include "thread.h"
+#include "threadstate.h"
+#include "git2/global.h"
+#include "streams/registry.h"
+#include "streams/mbedtls.h"
+#include "streams/openssl.h"
+#include "transports/smart.h"
+#include "transports/http.h"
+#include "transports/ssh.h"
+
+#ifdef GIT_WIN32
+# include "win32/w32_leakcheck.h"
+#endif
+
+/* Declarations for tuneable settings */
+extern size_t git_mwindow__window_size;
+extern size_t git_mwindow__mapped_limit;
+extern size_t git_mwindow__file_limit;
+extern size_t git_indexer__max_objects;
+extern bool git_disable_pack_keep_file_checks;
+extern int git_odb__packed_priority;
+extern int git_odb__loose_priority;
+
+char *git__user_agent;
+char *git__ssl_ciphers;
+
+static void libgit2_settings_global_shutdown(void)
+{
+       git__free(git__user_agent);
+       git__free(git__ssl_ciphers);
+       git_repository__free_extensions();
+}
+
+static int git_libgit2_settings_global_init(void)
+{
+       return git_runtime_shutdown_register(libgit2_settings_global_shutdown);
+}
+
+int git_libgit2_init(void)
+{
+       static git_runtime_init_fn init_fns[] = {
+#ifdef GIT_WIN32
+               git_win32_leakcheck_global_init,
+#endif
+               git_allocator_global_init,
+               git_threadstate_global_init,
+               git_threads_global_init,
+               git_hash_global_init,
+               git_sysdir_global_init,
+               git_filter_global_init,
+               git_merge_driver_global_init,
+               git_transport_ssh_global_init,
+               git_stream_registry_global_init,
+               git_openssl_stream_global_init,
+               git_mbedtls_stream_global_init,
+               git_mwindow_global_init,
+               git_pool_global_init,
+               git_libgit2_settings_global_init
+       };
+
+       return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
+}
+
+int git_libgit2_init_count(void)
+{
+       return git_runtime_init_count();
+}
+
+int git_libgit2_shutdown(void)
+{
+       return git_runtime_shutdown();
+}
+
+int git_libgit2_version(int *major, int *minor, int *rev)
+{
+       *major = LIBGIT2_VER_MAJOR;
+       *minor = LIBGIT2_VER_MINOR;
+       *rev = LIBGIT2_VER_REVISION;
+
+       return 0;
+}
+
+int git_libgit2_features(void)
+{
+       return 0
+#ifdef GIT_THREADS
+               | GIT_FEATURE_THREADS
+#endif
+#ifdef GIT_HTTPS
+               | GIT_FEATURE_HTTPS
+#endif
+#if defined(GIT_SSH)
+               | GIT_FEATURE_SSH
+#endif
+#if defined(GIT_USE_NSEC)
+               | GIT_FEATURE_NSEC
+#endif
+       ;
+}
+
+static int config_level_to_sysdir(int *out, int config_level)
+{
+       switch (config_level) {
+       case GIT_CONFIG_LEVEL_SYSTEM:
+               *out = GIT_SYSDIR_SYSTEM;
+               return 0;
+       case GIT_CONFIG_LEVEL_XDG:
+               *out = GIT_SYSDIR_XDG;
+               return 0;
+       case GIT_CONFIG_LEVEL_GLOBAL:
+               *out = GIT_SYSDIR_GLOBAL;
+               return 0;
+       case GIT_CONFIG_LEVEL_PROGRAMDATA:
+               *out = GIT_SYSDIR_PROGRAMDATA;
+               return 0;
+       default:
+               break;
+       }
+
+       git_error_set(
+               GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
+       return -1;
+}
+
+const char *git_libgit2__user_agent(void)
+{
+       return git__user_agent;
+}
+
+const char *git_libgit2__ssl_ciphers(void)
+{
+       return git__ssl_ciphers;
+}
+
+int git_libgit2_opts(int key, ...)
+{
+       int error = 0;
+       va_list ap;
+
+       va_start(ap, key);
+
+       switch (key) {
+       case GIT_OPT_SET_MWINDOW_SIZE:
+               git_mwindow__window_size = va_arg(ap, size_t);
+               break;
+
+       case GIT_OPT_GET_MWINDOW_SIZE:
+               *(va_arg(ap, size_t *)) = git_mwindow__window_size;
+               break;
+
+       case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
+               git_mwindow__mapped_limit = va_arg(ap, size_t);
+               break;
+
+       case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
+               *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
+               break;
+
+       case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
+               git_mwindow__file_limit = va_arg(ap, size_t);
+               break;
+
+       case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
+               *(va_arg(ap, size_t *)) = git_mwindow__file_limit;
+               break;
+
+       case GIT_OPT_GET_SEARCH_PATH:
+               {
+                       int sysdir = va_arg(ap, int);
+                       git_buf *out = va_arg(ap, git_buf *);
+                       const git_buf *tmp;
+                       int level;
+
+                       if ((error = config_level_to_sysdir(&level, sysdir)) < 0 ||
+                           (error = git_buf_sanitize(out)) < 0 ||
+                           (error = git_sysdir_get(&tmp, level)) < 0)
+                               break;
+
+                       error = git_buf_sets(out, tmp->ptr);
+               }
+               break;
+
+       case GIT_OPT_SET_SEARCH_PATH:
+               {
+                       int level;
+
+                       if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0)
+                               error = git_sysdir_set(level, va_arg(ap, const char *));
+               }
+               break;
+
+       case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
+               {
+                       git_object_t type = (git_object_t)va_arg(ap, int);
+                       size_t size = va_arg(ap, size_t);
+                       error = git_cache_set_max_object_size(type, size);
+                       break;
+               }
+
+       case GIT_OPT_SET_CACHE_MAX_SIZE:
+               git_cache__max_storage = va_arg(ap, ssize_t);
+               break;
+
+       case GIT_OPT_ENABLE_CACHING:
+               git_cache__enabled = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_GET_CACHED_MEMORY:
+               *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
+               *(va_arg(ap, ssize_t *)) = git_cache__max_storage;
+               break;
+
+       case GIT_OPT_GET_TEMPLATE_PATH:
+               {
+                       git_buf *out = va_arg(ap, git_buf *);
+                       const git_buf *tmp;
+
+                       if ((error = git_buf_sanitize(out)) < 0 ||
+                           (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0)
+                               break;
+
+                       error = git_buf_sets(out, tmp->ptr);
+               }
+               break;
+
+       case GIT_OPT_SET_TEMPLATE_PATH:
+               error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
+               break;
+
+       case GIT_OPT_SET_SSL_CERT_LOCATIONS:
+#ifdef GIT_OPENSSL
+               {
+                       const char *file = va_arg(ap, const char *);
+                       const char *path = va_arg(ap, const char *);
+                       error = git_openssl__set_cert_location(file, path);
+               }
+#elif defined(GIT_MBEDTLS)
+               {
+                       const char *file = va_arg(ap, const char *);
+                       const char *path = va_arg(ap, const char *);
+                       error = git_mbedtls__set_cert_location(file, path);
+               }
+#else
+               git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
+               error = -1;
+#endif
+               break;
+       case GIT_OPT_SET_USER_AGENT:
+               git__free(git__user_agent);
+               git__user_agent = git__strdup(va_arg(ap, const char *));
+               if (!git__user_agent) {
+                       git_error_set_oom();
+                       error = -1;
+               }
+
+               break;
+
+       case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
+               git_object__strict_input_validation = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
+               git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_SET_SSL_CIPHERS:
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+               {
+                       git__free(git__ssl_ciphers);
+                       git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
+                       if (!git__ssl_ciphers) {
+                               git_error_set_oom();
+                               error = -1;
+                       }
+               }
+#else
+               git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
+               error = -1;
+#endif
+               break;
+
+       case GIT_OPT_GET_USER_AGENT:
+               {
+                       git_buf *out = va_arg(ap, git_buf *);
+                       if ((error = git_buf_sanitize(out)) < 0)
+                               break;
+                       error = git_buf_sets(out, git__user_agent);
+               }
+               break;
+
+       case GIT_OPT_ENABLE_OFS_DELTA:
+               git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_ENABLE_FSYNC_GITDIR:
+               git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_GET_WINDOWS_SHAREMODE:
+#ifdef GIT_WIN32
+               *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
+#endif
+               break;
+
+       case GIT_OPT_SET_WINDOWS_SHAREMODE:
+#ifdef GIT_WIN32
+               git_win32__createfile_sharemode = va_arg(ap, unsigned long);
+#endif
+               break;
+
+       case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
+               git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_SET_ALLOCATOR:
+               error = git_allocator_setup(va_arg(ap, git_allocator *));
+               break;
+
+       case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
+               git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_SET_PACK_MAX_OBJECTS:
+               git_indexer__max_objects = va_arg(ap, size_t);
+               break;
+
+       case GIT_OPT_GET_PACK_MAX_OBJECTS:
+               *(va_arg(ap, size_t *)) = git_indexer__max_objects;
+               break;
+
+       case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
+               git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
+               git_http__expect_continue = (va_arg(ap, int) != 0);
+               break;
+
+       case GIT_OPT_SET_ODB_PACKED_PRIORITY:
+               git_odb__packed_priority = va_arg(ap, int);
+               break;
+
+       case GIT_OPT_SET_ODB_LOOSE_PRIORITY:
+               git_odb__loose_priority = va_arg(ap, int);
+               break;
+
+       case GIT_OPT_SET_EXTENSIONS:
+               {
+                       const char **extensions = va_arg(ap, const char **);
+                       size_t len = va_arg(ap, size_t);
+                       error = git_repository__set_extensions(extensions, len);
+               }
+               break;
+
+       case GIT_OPT_GET_EXTENSIONS:
+               {
+                       git_strarray *out = va_arg(ap, git_strarray *);
+                       char **extensions;
+                       size_t len;
+
+                       if ((error = git_repository__extensions(&extensions, &len)) < 0)
+                               break;
+
+                       out->strings = extensions;
+                       out->count = len;
+               }
+               break;
+
+       default:
+               git_error_set(GIT_ERROR_INVALID, "invalid option key");
+               error = -1;
+       }
+
+       va_end(ap);
+
+       return error;
+}
diff --git a/src/libgit2.h b/src/libgit2.h
new file mode 100644 (file)
index 0000000..a898367
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_libgit2_h__
+#define INCLUDE_libgit2_h__
+
+extern int git_libgit2_init_count(void);
+
+extern const char *git_libgit2__user_agent(void);
+extern const char *git_libgit2__ssl_ciphers(void);
+
+#endif
index 409cdbd3c227ac8499d5d455a086c169f9522373..b69d55e2ee2b23e7591d5e3627b012697179a199 100644 (file)
@@ -43,7 +43,8 @@ static int mailmap_entry_cmp(const void *a_raw, const void *b_raw)
        const git_mailmap_entry *b = (const git_mailmap_entry *)b_raw;
        int cmp;
 
-       assert(a && b && a->replace_email && b->replace_email);
+       GIT_ASSERT_ARG(a && a->replace_email);
+       GIT_ASSERT_ARG(b && b->replace_email);
 
        cmp = git__strcmp(a->replace_email, b->replace_email);
        if (cmp)
@@ -185,7 +186,8 @@ static int mailmap_add_entry_unterminated(
        git_mailmap_entry *entry = git__calloc(1, sizeof(git_mailmap_entry));
        GIT_ERROR_CHECK_ALLOC(entry);
 
-       assert(mm && replace_email && *replace_email);
+       GIT_ASSERT_ARG(mm);
+       GIT_ASSERT_ARG(replace_email && *replace_email);
 
        if (real_name_size > 0) {
                entry->real_name = git__substrdup(real_name, real_name_size);
@@ -290,7 +292,8 @@ static int mailmap_add_blob(
        git_buf content = GIT_BUF_INIT;
        int error;
 
-       assert(mm && repo);
+       GIT_ASSERT_ARG(mm);
+       GIT_ASSERT_ARG(repo);
 
        error = git_revparse_single(&object, repo, rev);
        if (error < 0)
@@ -327,6 +330,10 @@ static int mailmap_add_file_ondisk(
        if (error < 0)
                goto cleanup;
 
+       error = git_path_validate_workdir_buf(repo, &fullpath);
+       if (error < 0)
+               goto cleanup;
+
        error = git_futils_readbuffer(&content, fullpath.ptr);
        if (error < 0)
                goto cleanup;
@@ -350,8 +357,6 @@ static void mailmap_add_from_repository(git_mailmap *mm, git_repository *repo)
        const char *rev = NULL;
        const char *path = NULL;
 
-       assert(mm && repo);
-
        /* If we're in a bare repo, default blob to 'HEAD:.mailmap' */
        if (repo->is_bare)
                rev = MM_BLOB_DEFAULT;
@@ -389,9 +394,14 @@ static void mailmap_add_from_repository(git_mailmap *mm, git_repository *repo)
 
 int git_mailmap_from_repository(git_mailmap **out, git_repository *repo)
 {
-       int error = git_mailmap_new(out);
-       if (error < 0)
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+
+       if ((error = git_mailmap_new(out)) < 0)
                return error;
+
        mailmap_add_from_repository(*out, repo);
        return 0;
 }
@@ -408,7 +418,7 @@ const git_mailmap_entry *git_mailmap_entry_lookup(
        git_mailmap_entry needle = { NULL };
        needle.replace_email = (char *)email;
 
-       assert(email);
+       GIT_ASSERT_ARG_WITH_RETVAL(email, NULL);
 
        if (!mm)
                return NULL;
@@ -431,7 +441,8 @@ const git_mailmap_entry *git_mailmap_entry_lookup(
                if (git__strcmp(entry->replace_email, email))
                        break; /* it's a different email, so we're done looking */
 
-               assert(entry->replace_name); /* should be specific */
+                /* should be specific */
+               GIT_ASSERT_WITH_RETVAL(entry->replace_name, NULL);
                if (!name || !git__strcmp(entry->replace_name, name))
                        return entry;
        }
@@ -447,7 +458,9 @@ int git_mailmap_resolve(
        const char *name, const char *email)
 {
        const git_mailmap_entry *entry = NULL;
-       assert(name && email);
+
+       GIT_ASSERT(name);
+       GIT_ASSERT(email);
 
        *real_name = name;
        *real_email = email;
index 6328d8cf45e7170742bbd5cd1c270b73643da57f..01931d199c008a351ad731151634bdf77c6f4cf5 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -36,9 +36,9 @@ typedef struct { /* memory mapped buffer      */
 } git_map;
 
 #define GIT_MMAP_VALIDATE(out, len, prot, flags) do { \
-       assert(out != NULL && len > 0); \
-       assert((prot & GIT_PROT_WRITE) || (prot & GIT_PROT_READ)); \
-       assert((flags & GIT_MAP_FIXED) == 0); } while (0)
+       GIT_ASSERT(out != NULL && len > 0); \
+       GIT_ASSERT((prot & GIT_PROT_WRITE) || (prot & GIT_PROT_READ)); \
+       GIT_ASSERT((flags & GIT_MAP_FIXED) == 0); } while (0)
 
 extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset);
 extern int p_munmap(git_map *map);
index 2f6bf6fe79b3d8e0205333adcee7e70e9a5cc839..d838e4ba92ca5ab3bb53311316f5df8d0393e315 100644 (file)
@@ -112,7 +112,7 @@ static int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_r
        if (commit == NULL)
                goto on_error;
 
-       if (git_merge__bases_many(&result, walk, commit, &list) < 0)
+       if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0)
                goto on_error;
 
        if (!result) {
@@ -139,7 +139,9 @@ int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const
        git_commit_list *result = NULL;
        int error = 0;
 
-       assert(out && repo && input_array);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(input_array);
 
        if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0)
                return error;
@@ -159,7 +161,9 @@ int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length,
        int error = 0;
        git_array_oid_t array;
 
-       assert(out && repo && input_array);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(input_array);
 
        if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0)
                return error;
@@ -193,7 +197,9 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co
        unsigned int i;
        int error = -1;
 
-       assert(out && repo && input_array);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(input_array);
 
        if (length < 2) {
                git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor");
@@ -237,7 +243,7 @@ static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_reposi
        if (commit == NULL)
                goto on_error;
 
-       if (git_merge__bases_many(&result, walk, commit, &list) < 0)
+       if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0)
                goto on_error;
 
        if (!result) {
@@ -372,7 +378,11 @@ static int clear_commit_marks(git_commit_list_node *commit, unsigned int mark)
 }
 
 static int paint_down_to_common(
-       git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
+               git_commit_list **out,
+               git_revwalk *walk,
+               git_commit_list_node *one,
+               git_vector *twos,
+               uint32_t minimum_generation)
 {
        git_pqueue list;
        git_commit_list *result = NULL;
@@ -381,7 +391,7 @@ static int paint_down_to_common(
        int error;
        unsigned int i;
 
-       if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0)
+       if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_generation_cmp) < 0)
                return -1;
 
        one->flags |= PARENT1;
@@ -393,7 +403,6 @@ static int paint_down_to_common(
                        return -1;
 
                two->flags |= PARENT2;
-
                if (git_pqueue_insert(&list, two) < 0)
                        return -1;
        }
@@ -421,6 +430,8 @@ static int paint_down_to_common(
                        git_commit_list_node *p = commit->parents[i];
                        if ((p->flags & flags) == flags)
                                continue;
+                       if (p->generation < minimum_generation)
+                               continue;
 
                        if ((error = git_commit_list_parse(walk, p)) < 0)
                                return error;
@@ -436,7 +447,7 @@ static int paint_down_to_common(
        return 0;
 }
 
-static int remove_redundant(git_revwalk *walk, git_vector *commits)
+static int remove_redundant(git_revwalk *walk, git_vector *commits, uint32_t minimum_generation)
 {
        git_vector work = GIT_VECTOR_INIT;
        unsigned char *redundant;
@@ -472,7 +483,7 @@ static int remove_redundant(git_revwalk *walk, git_vector *commits)
                                goto done;
                }
 
-               error = paint_down_to_common(&common, walk, commit, &work);
+               error = paint_down_to_common(&common, walk, commit, &work, minimum_generation);
                if (error < 0)
                        goto done;
 
@@ -504,7 +515,12 @@ done:
        return error;
 }
 
-int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
+int git_merge__bases_many(
+               git_commit_list **out,
+               git_revwalk *walk,
+               git_commit_list_node *one,
+               git_vector *twos,
+               uint32_t minimum_generation)
 {
        int error;
        unsigned int i;
@@ -526,7 +542,7 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
        if (git_commit_list_parse(walk, one) < 0)
                return -1;
 
-       error = paint_down_to_common(&result, walk, one, twos);
+       error = paint_down_to_common(&result, walk, one, twos, minimum_generation);
        if (error < 0)
                return error;
 
@@ -553,7 +569,7 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
 
                if ((error = clear_commit_marks(one, ALL_FLAGS)) < 0 ||
                    (error = clear_commit_marks_many(twos, ALL_FLAGS)) < 0 ||
-                   (error = remove_redundant(walk, &redundant)) < 0) {
+                   (error = remove_redundant(walk, &redundant, minimum_generation)) < 0) {
                        git_vector_free(&redundant);
                        return error;
                }
@@ -581,7 +597,8 @@ int git_repository_mergehead_foreach(
        git_oid oid;
        int error = 0;
 
-       assert(repo && cb);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(cb);
 
        if ((error = git_buf_joinpath(&merge_head_path, repo->gitdir,
                GIT_MERGE_HEAD_FILE)) < 0)
@@ -650,7 +667,9 @@ static int merge_conflict_resolve_trivial(
        git_index_entry const *result = NULL;
        int error = 0;
 
-       assert(resolved && diff_list && conflict);
+       GIT_ASSERT_ARG(resolved);
+       GIT_ASSERT_ARG(diff_list);
+       GIT_ASSERT_ARG(conflict);
 
        *resolved = 0;
 
@@ -733,7 +752,9 @@ static int merge_conflict_resolve_one_removed(
        int ours_changed, theirs_changed;
        int error = 0;
 
-       assert(resolved && diff_list && conflict);
+       GIT_ASSERT_ARG(resolved);
+       GIT_ASSERT_ARG(diff_list);
+       GIT_ASSERT_ARG(conflict);
 
        *resolved = 0;
 
@@ -773,7 +794,9 @@ static int merge_conflict_resolve_one_renamed(
        git_index_entry *merged;
        int error = 0;
 
-       assert(resolved && diff_list && conflict);
+       GIT_ASSERT_ARG(resolved);
+       GIT_ASSERT_ARG(diff_list);
+       GIT_ASSERT_ARG(conflict);
 
        *resolved = 0;
 
@@ -793,8 +816,11 @@ static int merge_conflict_resolve_one_renamed(
                conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED)
                return 0;
 
-       ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0);
-       theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0);
+       ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0) ||
+               (conflict->ancestor_entry.mode != conflict->our_entry.mode);
+
+       theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0) ||
+               (conflict->ancestor_entry.mode != conflict->their_entry.mode);
 
        /* if both are modified (and not to a common target) require a merge */
        if (ours_changed && theirs_changed &&
@@ -917,7 +943,9 @@ static int merge_conflict_resolve_contents(
        bool fallback = false;
        int error;
 
-       assert(resolved && diff_list && conflict);
+       GIT_ASSERT_ARG(resolved);
+       GIT_ASSERT_ARG(diff_list);
+       GIT_ASSERT_ARG(conflict);
 
        *resolved = 0;
 
@@ -1126,7 +1154,7 @@ static void deletes_by_oid_free(git_oidmap *map) {
        git_oidmap_free(map);
 }
 
-static int deletes_by_oid_enqueue(git_oidmap *map, git_poolpool, const git_oid *id, size_t idx)
+static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid *id, size_t idx)
 {
        deletes_by_oid_queue *queue;
        size_t *array_entry;
@@ -1517,9 +1545,11 @@ int git_merge_diff_list__find_renames(
        size_t src_count, tgt_count, i;
        int error = 0;
 
-       assert(diff_list && opts);
+       GIT_ASSERT_ARG(diff_list);
+       GIT_ASSERT_ARG(opts);
 
-       if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0)
+       if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0 ||
+           !diff_list->conflicts.length)
                return 0;
 
        similarity_ours = git__calloc(diff_list->conflicts.length,
@@ -1843,7 +1873,8 @@ static int merge_normalize_opts(
        git_config_entry *entry = NULL;
        int error = 0;
 
-       assert(repo && opts);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(opts);
 
        if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
                return error;
@@ -2070,7 +2101,8 @@ int git_merge__iterators(
        size_t i;
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -2154,7 +2186,8 @@ int git_merge_trees(
        git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
        int error;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        /* if one side is treesame to the ancestor, take the other side */
        if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) {
@@ -2258,8 +2291,11 @@ static int create_virtual_base(
        result->type = GIT_ANNOTATED_COMMIT_VIRTUAL;
        result->index = index;
 
-       insert_head_ids(&result->parents, one);
-       insert_head_ids(&result->parents, two);
+       if (insert_head_ids(&result->parents, one) < 0 ||
+               insert_head_ids(&result->parents, two) < 0) {
+               git_annotated_commit_free(result);
+               return -1;
+       }
 
        *out = result;
        return 0;
@@ -2333,7 +2369,7 @@ done:
 
        git_annotated_commit_free(other);
        git_annotated_commit_free(new_base);
-       git_oidarray_free(&bases);
+       git_oidarray_dispose(&bases);
        git_array_clear(head_ids);
        return error;
 }
@@ -2441,7 +2477,8 @@ static int write_merge_head(
        size_t i;
        int error = 0;
 
-       assert(repo && heads);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(heads);
 
        if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 ||
                (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
@@ -2469,7 +2506,7 @@ static int write_merge_mode(git_repository *repo)
        git_buf file_path = GIT_BUF_INIT;
        int error = 0;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 ||
                (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
@@ -2689,7 +2726,8 @@ static int write_merge_msg(
        char sep = 0;
        int error = 0;
 
-       assert(repo && heads);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(heads);
 
        entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
        GIT_ERROR_CHECK_ALLOC(entries);
@@ -2800,7 +2838,9 @@ int git_merge__setup(
 {
        int error = 0;
 
-       assert (repo && our_head && heads);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(our_head);
+       GIT_ASSERT_ARG(heads);
 
        if ((error = git_repository__set_orig_head(repo, git_annotated_commit_id(our_head))) == 0 &&
                (error = write_merge_head(repo, heads, heads_len)) == 0 &&
@@ -2824,7 +2864,9 @@ static int merge_ancestor_head(
        size_t i, alloc_len;
        int error = 0;
 
-       assert(repo && our_head && their_heads);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(our_head);
+       GIT_ASSERT_ARG(their_heads);
 
        GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, their_heads_len, 1);
        oids = git__calloc(alloc_len, sizeof(git_oid));
@@ -3202,7 +3244,10 @@ int git_merge_analysis_for_ref(
        int error = 0;
        bool unborn;
 
-       assert(analysis_out && preference_out && repo && their_heads && their_heads_len > 0);
+       GIT_ASSERT_ARG(analysis_out);
+       GIT_ASSERT_ARG(preference_out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(their_heads && their_heads_len > 0);
 
        if (their_heads_len != 1) {
                git_error_set(GIT_ERROR_MERGE, "can only merge a single branch");
@@ -3284,7 +3329,8 @@ int git_merge(
        unsigned int checkout_strategy;
        int error = 0;
 
-       assert(repo && their_heads && their_heads_len > 0);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(their_heads && their_heads_len > 0);
 
        if (their_heads_len != 1) {
                git_error_set(GIT_ERROR_MERGE, "can only merge a single branch");
index b0a7de2becf4dda9bd96ede2196dbe0d4bc1620a..3e7f80c6ee2a80a6e115c7e72e589162c9b3c495 100644 (file)
@@ -129,7 +129,8 @@ int git_merge__bases_many(
        git_commit_list **out,
        git_revwalk *walk,
        git_commit_list_node *one,
-       git_vector *twos);
+       git_vector *twos,
+       uint32_t minimum_generation);
 
 /*
  * Three-way tree differencing
index 666349b156b01095c79d20f5327cd41ed66214b3..17c386a143c738ee18df5bd41ec62bb434dfa7e1 100644 (file)
@@ -8,7 +8,7 @@
 #include "merge_driver.h"
 
 #include "vector.h"
-#include "global.h"
+#include "runtime.h"
 #include "merge.h"
 #include "git2/merge.h"
 #include "git2/sys/merge.h"
@@ -32,33 +32,38 @@ static struct merge_driver_registry merge_driver_registry;
 
 static void git_merge_driver_global_shutdown(void);
 
-git_repository* git_merge_driver_source_repo(const git_merge_driver_source *src)
+git_repository *git_merge_driver_source_repo(
+       const git_merge_driver_source *src)
 {
-       assert(src);
+       GIT_ASSERT_ARG_WITH_RETVAL(src, NULL);
        return src->repo;
 }
 
-const git_index_entry* git_merge_driver_source_ancestor(const git_merge_driver_source *src)
+const git_index_entry *git_merge_driver_source_ancestor(
+       const git_merge_driver_source *src)
 {
-       assert(src);
+       GIT_ASSERT_ARG_WITH_RETVAL(src, NULL);
        return src->ancestor;
 }
 
-const git_index_entry* git_merge_driver_source_ours(const git_merge_driver_source *src)
+const git_index_entry *git_merge_driver_source_ours(
+       const git_merge_driver_source *src)
 {
-       assert(src);
+       GIT_ASSERT_ARG_WITH_RETVAL(src, NULL);
        return src->ours;
 }
 
-const git_index_entry* git_merge_driver_source_theirs(const git_merge_driver_source *src)
+const git_index_entry *git_merge_driver_source_theirs(
+       const git_merge_driver_source *src)
 {
-       assert(src);
+       GIT_ASSERT_ARG_WITH_RETVAL(src, NULL);
        return src->theirs;
 }
 
-const git_merge_file_options* git_merge_driver_source_file_options(const git_merge_driver_source *src)
+const git_merge_file_options *git_merge_driver_source_file_options(
+       const git_merge_driver_source *src)
 {
-       assert(src);
+       GIT_ASSERT_ARG_WITH_RETVAL(src, NULL);
        return src->file_opts;
 }
 
@@ -209,7 +214,7 @@ int git_merge_driver_global_init(void)
                        merge_driver_name__binary, &git_merge_driver__binary)) < 0)
                goto done;
 
-       git__on_shutdown(git_merge_driver_global_shutdown);
+       error = git_runtime_shutdown_register(git_merge_driver_global_shutdown);
 
 done:
        if (error < 0)
@@ -262,7 +267,8 @@ int git_merge_driver_register(const char *name, git_merge_driver *driver)
 {
        int error;
 
-       assert(name && driver);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(driver);
 
        if (git_rwlock_wrlock(&merge_driver_registry.lock) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to lock merge driver registry");
index 755340fa9845f23b0dc05f019ba9c547be3916ab..bfa3ec52e488b03cd00e150ad8937ecee42af022 100644 (file)
@@ -36,7 +36,10 @@ static int merge_file_input_from_index(
 {
        int error = 0;
 
-       assert(input_out && odb_object_out && odb && entry);
+       GIT_ASSERT_ARG(input_out);
+       GIT_ASSERT_ARG(odb_object_out);
+       GIT_ASSERT_ARG(odb);
+       GIT_ASSERT_ARG(entry);
 
        if ((error = git_odb_read(odb_object_out, odb, &entry->id)) < 0)
                goto done;
@@ -241,7 +244,9 @@ int git_merge_file(
 {
        git_merge_file_input inputs[3] = { {0} };
 
-       assert(out && ours && theirs);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ours);
+       GIT_ASSERT_ARG(theirs);
 
        memset(out, 0x0, sizeof(git_merge_file_result));
 
@@ -268,7 +273,10 @@ int git_merge_file_from_index(
        git_odb_object *odb_object[3] = { 0 };
        int error = 0;
 
-       assert(out && repo && ours && theirs);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(ours);
+       GIT_ASSERT_ARG(theirs);
 
        memset(out, 0x0, sizeof(git_merge_file_result));
 
index 6c5a2379fc81567a8fed4b25eb8fe87c4188bcea..327b984fc7ce4df1993aafa2185aab91fe99621e 100644 (file)
@@ -28,8 +28,10 @@ int git_message_prettify(git_buf *message_out, const char *message, int strip_co
        int consecutive_empty_lines = 0;
        size_t i, line_length, rtrimmed_line_length;
        char *next_newline;
+       int error;
 
-       git_buf_sanitize(message_out);
+       if ((error = git_buf_sanitize(message_out)) < 0)
+               return error;
 
        for (i = 0; i < strlen(message); i += line_length) {
                next_newline = memchr(message + i, '\n', message_len - i);
index 21cfff497cfab7e670f48d85ab5dc638a9503278..6a885eddca57a17984f88f6670f949b242bcfc32 100644 (file)
@@ -7,13 +7,15 @@
 
 #include "midx.h"
 
+#include "array.h"
 #include "buffer.h"
+#include "filebuf.h"
 #include "futils.h"
 #include "hash.h"
 #include "odb.h"
 #include "pack.h"
-
-#define GIT_MIDX_FILE_MODE 0444
+#include "path.h"
+#include "repository.h"
 
 #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
 #define MIDX_VERSION 1
@@ -38,6 +40,8 @@ struct git_midx_chunk {
        size_t length;
 };
 
+typedef int (*midx_write_cb)(const char *buf, size_t size, void *cb_data);
+
 static int midx_error(const char *message)
 {
        git_error_set(GIT_ERROR_ODB, "invalid multi-pack-index file - %s", message);
@@ -116,7 +120,7 @@ static int midx_parse_oid_lookup(
                return midx_error("missing OID Lookup chunk");
        if (chunk_oid_lookup->length == 0)
                return midx_error("empty OID Lookup chunk");
-       if (chunk_oid_lookup->length != idx->num_objects * 20)
+       if (chunk_oid_lookup->length != idx->num_objects * GIT_OID_RAWSZ)
                return midx_error("OID Lookup chunk has wrong length");
 
        idx->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset);
@@ -181,9 +185,9 @@ int git_midx_parse(
                                         chunk_object_offsets = {0},
                                         chunk_object_large_offsets = {0};
 
-       assert(idx);
+       GIT_ASSERT_ARG(idx);
 
-       if (size < sizeof(struct git_midx_header) + 20)
+       if (size < sizeof(struct git_midx_header) + GIT_OID_RAWSZ)
                return midx_error("multi-pack index is too short");
 
        hdr = ((struct git_midx_header *)data);
@@ -203,7 +207,7 @@ int git_midx_parse(
        last_chunk_offset =
                        sizeof(struct git_midx_header) +
                        (1 + hdr->chunks) * 12;
-       trailer_offset = size - 20;
+       trailer_offset = size - GIT_OID_RAWSZ;
        if (trailer_offset < last_chunk_offset)
                return midx_error("wrong index size");
        git_oid_cpy(&idx->checksum, (git_oid *)(data + trailer_offset));
@@ -309,6 +313,10 @@ int git_midx_open(
        idx = git__calloc(1, sizeof(git_midx_file));
        GIT_ERROR_CHECK_ALLOC(idx);
 
+       error = git_buf_sets(&idx->filename, path);
+       if (error < 0)
+               return error;
+
        error = git_futils_mmap_ro(&idx->index_map, fd, 0, idx_size);
        p_close(fd);
        if (error < 0) {
@@ -325,6 +333,41 @@ int git_midx_open(
        return 0;
 }
 
+bool git_midx_needs_refresh(
+               const git_midx_file *idx,
+               const char *path)
+{
+       git_file fd = -1;
+       struct stat st;
+       ssize_t bytes_read;
+       git_oid idx_checksum = {{0}};
+
+       /* TODO: properly open the file without access time using O_NOATIME */
+       fd = git_futils_open_ro(path);
+       if (fd < 0)
+               return true;
+
+       if (p_fstat(fd, &st) < 0) {
+               p_close(fd);
+               return true;
+       }
+
+       if (!S_ISREG(st.st_mode) ||
+           !git__is_sizet(st.st_size) ||
+           (size_t)st.st_size != idx->index_map.len) {
+               p_close(fd);
+               return true;
+       }
+
+       bytes_read = p_pread(fd, &idx_checksum, GIT_OID_RAWSZ, st.st_size - GIT_OID_RAWSZ);
+       p_close(fd);
+
+       if (bytes_read != GIT_OID_RAWSZ)
+               return true;
+
+       return !git_oid_equal(&idx_checksum, &idx->checksum);
+}
+
 int git_midx_entry_find(
                git_midx_entry *e,
                git_midx_file *idx,
@@ -338,12 +381,12 @@ int git_midx_entry_find(
        const unsigned char *object_offset;
        off64_t offset;
 
-       assert(idx);
+       GIT_ASSERT_ARG(idx);
 
        hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]);
        lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1]));
 
-       pos = git_pack__lookup_sha1(idx->oid_lookup, 20, lo, hi, short_oid->id);
+       pos = git_pack__lookup_sha1(idx->oid_lookup, GIT_OID_RAWSZ, lo, hi, short_oid->id);
 
        if (pos >= 0) {
                /* An object matching exactly the oid was found */
@@ -399,13 +442,34 @@ int git_midx_entry_find(
        return 0;
 }
 
-void git_midx_close(git_midx_file *idx)
+int git_midx_foreach_entry(
+               git_midx_file *idx,
+               git_odb_foreach_cb cb,
+               void *data)
 {
-       assert(idx);
+       size_t i;
+       int error;
+
+       GIT_ASSERT_ARG(idx);
+
+       for (i = 0; i < idx->num_objects; ++i) {
+               if ((error = cb(&idx->oid_lookup[i], data)) != 0)
+                       return git_error_set_after_callback(error);
+       }
+
+       return error;
+}
+
+int git_midx_close(git_midx_file *idx)
+{
+       GIT_ASSERT_ARG(idx);
 
        if (idx->index_map.data)
                git_futils_mmap_free(&idx->index_map);
+
        git_vector_free(&idx->packfile_names);
+
+       return 0;
 }
 
 void git_midx_free(git_midx_file *idx)
@@ -413,6 +477,403 @@ void git_midx_free(git_midx_file *idx)
        if (!idx)
                return;
 
+       git_buf_dispose(&idx->filename);
        git_midx_close(idx);
        git__free(idx);
 }
+
+static int packfile__cmp(const void *a_, const void *b_)
+{
+       const struct git_pack_file *a = a_;
+       const struct git_pack_file *b = b_;
+
+       return strcmp(a->pack_name, b->pack_name);
+}
+
+int git_midx_writer_new(
+               git_midx_writer **out,
+               const char *pack_dir)
+{
+       git_midx_writer *w = git__calloc(1, sizeof(git_midx_writer));
+       GIT_ERROR_CHECK_ALLOC(w);
+
+       if (git_buf_sets(&w->pack_dir, pack_dir) < 0) {
+               git__free(w);
+               return -1;
+       }
+       git_path_squash_slashes(&w->pack_dir);
+
+       if (git_vector_init(&w->packs, 0, packfile__cmp) < 0) {
+               git_buf_dispose(&w->pack_dir);
+               git__free(w);
+               return -1;
+       }
+
+       *out = w;
+       return 0;
+}
+
+void git_midx_writer_free(git_midx_writer *w)
+{
+       struct git_pack_file *p;
+       size_t i;
+
+       if (!w)
+               return;
+
+       git_vector_foreach (&w->packs, i, p)
+               git_mwindow_put_pack(p);
+       git_vector_free(&w->packs);
+       git_buf_dispose(&w->pack_dir);
+       git__free(w);
+}
+
+int git_midx_writer_add(
+               git_midx_writer *w,
+               const char *idx_path)
+{
+       git_buf idx_path_buf = GIT_BUF_INIT;
+       int error;
+       struct git_pack_file *p;
+
+       error = git_path_prettify(&idx_path_buf, idx_path, git_buf_cstr(&w->pack_dir));
+       if (error < 0)
+               return error;
+
+       error = git_mwindow_get_pack(&p, git_buf_cstr(&idx_path_buf));
+       git_buf_dispose(&idx_path_buf);
+       if (error < 0)
+               return error;
+
+       error = git_vector_insert(&w->packs, p);
+       if (error < 0) {
+               git_mwindow_put_pack(p);
+               return error;
+       }
+
+       return 0;
+}
+
+typedef git_array_t(git_midx_entry) object_entry_array_t;
+
+struct object_entry_cb_state {
+       uint32_t pack_index;
+       object_entry_array_t *object_entries_array;
+};
+
+static int object_entry__cb(const git_oid *oid, off64_t offset, void *data)
+{
+       struct object_entry_cb_state *state = (struct object_entry_cb_state *)data;
+
+       git_midx_entry *entry = git_array_alloc(*state->object_entries_array);
+       GIT_ERROR_CHECK_ALLOC(entry);
+
+       git_oid_cpy(&entry->sha1, oid);
+       entry->offset = offset;
+       entry->pack_index = state->pack_index;
+
+       return 0;
+}
+
+static int object_entry__cmp(const void *a_, const void *b_)
+{
+       const git_midx_entry *a = (const git_midx_entry *)a_;
+       const git_midx_entry *b = (const git_midx_entry *)b_;
+
+       return git_oid_cmp(&a->sha1, &b->sha1);
+}
+
+static int write_offset(off64_t offset, midx_write_cb write_cb, void *cb_data)
+{
+       int error;
+       uint32_t word;
+
+       word = htonl((uint32_t)((offset >> 32) & 0xffffffffu));
+       error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+       word = htonl((uint32_t)((offset >> 0) & 0xffffffffu));
+       error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+static int write_chunk_header(int chunk_id, off64_t offset, midx_write_cb write_cb, void *cb_data)
+{
+       uint32_t word = htonl(chunk_id);
+       int error = write_cb((const char *)&word, sizeof(word), cb_data);
+       if (error < 0)
+               return error;
+       return write_offset(offset, write_cb, cb_data);
+
+       return 0;
+}
+
+static int midx_write_buf(const char *buf, size_t size, void *data)
+{
+       git_buf *b = (git_buf *)data;
+       return git_buf_put(b, buf, size);
+}
+
+struct midx_write_hash_context {
+       midx_write_cb write_cb;
+       void *cb_data;
+       git_hash_ctx *ctx;
+};
+
+static int midx_write_hash(const char *buf, size_t size, void *data)
+{
+       struct midx_write_hash_context *ctx = (struct midx_write_hash_context *)data;
+       int error;
+
+       error = git_hash_update(ctx->ctx, buf, size);
+       if (error < 0)
+               return error;
+
+       return ctx->write_cb(buf, size, ctx->cb_data);
+}
+
+static int midx_write(
+               git_midx_writer *w,
+               midx_write_cb write_cb,
+               void *cb_data)
+{
+       int error = 0;
+       size_t i;
+       struct git_pack_file *p;
+       struct git_midx_header hdr = {0};
+       uint32_t oid_fanout_count;
+       uint32_t object_large_offsets_count;
+       uint32_t oid_fanout[256];
+       off64_t offset;
+       git_buf packfile_names = GIT_BUF_INIT,
+               oid_lookup = GIT_BUF_INIT,
+               object_offsets = GIT_BUF_INIT,
+               object_large_offsets = GIT_BUF_INIT;
+       git_oid idx_checksum = {{0}};
+       git_midx_entry *entry;
+       object_entry_array_t object_entries_array = GIT_ARRAY_INIT;
+       git_vector object_entries = GIT_VECTOR_INIT;
+       git_hash_ctx ctx;
+       struct midx_write_hash_context hash_cb_data = {0};
+
+       hdr.signature = htonl(MIDX_SIGNATURE);
+       hdr.version = MIDX_VERSION;
+       hdr.object_id_version = MIDX_OBJECT_ID_VERSION;
+       hdr.base_midx_files = 0;
+
+       hash_cb_data.write_cb = write_cb;
+       hash_cb_data.cb_data = cb_data;
+       hash_cb_data.ctx = &ctx;
+
+       error = git_hash_ctx_init(&ctx);
+       if (error < 0)
+               return error;
+       cb_data = &hash_cb_data;
+       write_cb = midx_write_hash;
+
+       git_vector_sort(&w->packs);
+       git_vector_foreach (&w->packs, i, p) {
+               git_buf relative_index = GIT_BUF_INIT;
+               struct object_entry_cb_state state = {0};
+               size_t path_len;
+
+               state.pack_index = (uint32_t)i;
+               state.object_entries_array = &object_entries_array;
+
+               error = git_buf_sets(&relative_index, p->pack_name);
+               if (error < 0)
+                       goto cleanup;
+               error = git_path_make_relative(&relative_index, git_buf_cstr(&w->pack_dir));
+               if (error < 0) {
+                       git_buf_dispose(&relative_index);
+                       goto cleanup;
+               }
+               path_len = git_buf_len(&relative_index);
+               if (path_len <= strlen(".pack") || git__suffixcmp(git_buf_cstr(&relative_index), ".pack") != 0) {
+                       git_buf_dispose(&relative_index);
+                       git_error_set(GIT_ERROR_INVALID, "invalid packfile name: '%s'", p->pack_name);
+                       error = -1;
+                       goto cleanup;
+               }
+               path_len -= strlen(".pack");
+
+               git_buf_put(&packfile_names, git_buf_cstr(&relative_index), path_len);
+               git_buf_puts(&packfile_names, ".idx");
+               git_buf_putc(&packfile_names, '\0');
+               git_buf_dispose(&relative_index);
+
+               error = git_pack_foreach_entry_offset(p, object_entry__cb, &state);
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /* Sort the object entries. */
+       error = git_vector_init(&object_entries, git_array_size(object_entries_array), object_entry__cmp);
+       if (error < 0)
+               goto cleanup;
+       git_array_foreach (object_entries_array, i, entry) {
+               if ((error = git_vector_set(NULL, &object_entries, i, entry)) < 0)
+                       goto cleanup;
+       }
+       git_vector_set_sorted(&object_entries, 0);
+       git_vector_sort(&object_entries);
+       git_vector_uniq(&object_entries, NULL);
+
+       /* Pad the packfile names so it is a multiple of four. */
+       while (git_buf_len(&packfile_names) & 3)
+               git_buf_putc(&packfile_names, '\0');
+
+       /* Fill the OID Fanout table. */
+       oid_fanout_count = 0;
+       for (i = 0; i < 256; i++) {
+               while (oid_fanout_count < git_vector_length(&object_entries) &&
+                      ((const git_midx_entry *)git_vector_get(&object_entries, oid_fanout_count))->sha1.id[0] <= i)
+                       ++oid_fanout_count;
+               oid_fanout[i] = htonl(oid_fanout_count);
+       }
+
+       /* Fill the OID Lookup table. */
+       git_vector_foreach (&object_entries, i, entry) {
+               error = git_buf_put(&oid_lookup, (const char *)&entry->sha1, sizeof(entry->sha1));
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /* Fill the Object Offsets and Object Large Offsets tables. */
+       object_large_offsets_count = 0;
+       git_vector_foreach (&object_entries, i, entry) {
+               uint32_t word;
+
+               word = htonl((uint32_t)entry->pack_index);
+               error = git_buf_put(&object_offsets, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+               if (entry->offset >= 0x80000000l) {
+                       word = htonl(0x80000000u | object_large_offsets_count++);
+                       if ((error = write_offset(entry->offset, midx_write_buf, &object_large_offsets)) < 0)
+                               goto cleanup;
+               } else {
+                       word = htonl((uint32_t)entry->offset & 0x7fffffffu);
+               }
+
+               error = git_buf_put(&object_offsets, (const char *)&word, sizeof(word));
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /* Write the header. */
+       hdr.packfiles = htonl((uint32_t)git_vector_length(&w->packs));
+       hdr.chunks = 4;
+       if (git_buf_len(&object_large_offsets) > 0)
+               hdr.chunks++;
+       error = write_cb((const char *)&hdr, sizeof(hdr), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Write the chunk headers. */
+       offset = sizeof(hdr) + (hdr.chunks + 1) * 12;
+       error = write_chunk_header(MIDX_PACKFILE_NAMES_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += git_buf_len(&packfile_names);
+       error = write_chunk_header(MIDX_OID_FANOUT_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += sizeof(oid_fanout);
+       error = write_chunk_header(MIDX_OID_LOOKUP_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += git_buf_len(&oid_lookup);
+       error = write_chunk_header(MIDX_OBJECT_OFFSETS_ID, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+       offset += git_buf_len(&object_offsets);
+       if (git_buf_len(&object_large_offsets) > 0) {
+               error = write_chunk_header(MIDX_OBJECT_LARGE_OFFSETS_ID, offset, write_cb, cb_data);
+               if (error < 0)
+                       goto cleanup;
+               offset += git_buf_len(&object_large_offsets);
+       }
+       error = write_chunk_header(0, offset, write_cb, cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Write all the chunks. */
+       error = write_cb(git_buf_cstr(&packfile_names), git_buf_len(&packfile_names), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb((const char *)oid_fanout, sizeof(oid_fanout), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&oid_lookup), git_buf_len(&oid_lookup), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&object_offsets), git_buf_len(&object_offsets), cb_data);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb(git_buf_cstr(&object_large_offsets), git_buf_len(&object_large_offsets), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+       /* Finalize the checksum and write the trailer. */
+       error = git_hash_final(&idx_checksum, &ctx);
+       if (error < 0)
+               goto cleanup;
+       error = write_cb((const char *)&idx_checksum, sizeof(idx_checksum), cb_data);
+       if (error < 0)
+               goto cleanup;
+
+cleanup:
+       git_array_clear(object_entries_array);
+       git_vector_free(&object_entries);
+       git_buf_dispose(&packfile_names);
+       git_buf_dispose(&oid_lookup);
+       git_buf_dispose(&object_offsets);
+       git_buf_dispose(&object_large_offsets);
+       git_hash_ctx_cleanup(&ctx);
+       return error;
+}
+
+static int midx_write_filebuf(const char *buf, size_t size, void *data)
+{
+       git_filebuf *f = (git_filebuf *)data;
+       return git_filebuf_write(f, buf, size);
+}
+
+int git_midx_writer_commit(
+               git_midx_writer *w)
+{
+       int error;
+       int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER;
+       git_buf midx_path = GIT_BUF_INIT;
+       git_filebuf output = GIT_FILEBUF_INIT;
+
+       error = git_buf_joinpath(&midx_path, git_buf_cstr(&w->pack_dir), "multi-pack-index");
+       if (error < 0)
+               return error;
+
+       if (git_repository__fsync_gitdir)
+               filebuf_flags |= GIT_FILEBUF_FSYNC;
+       error = git_filebuf_open(&output, git_buf_cstr(&midx_path), filebuf_flags, 0644);
+       git_buf_dispose(&midx_path);
+       if (error < 0)
+               return error;
+
+       error = midx_write(w, midx_write_filebuf, &output);
+       if (error < 0) {
+               git_filebuf_cleanup(&output);
+               return error;
+       }
+
+       return git_filebuf_commit(&output);
+}
+
+int git_midx_writer_dump(
+               git_buf *midx,
+               git_midx_writer *w)
+{
+       return midx_write(w, midx_write_buf, midx);
+}
index e6a64cd8158aadd057f5b03798e4cd91fdd194e1..4ce17ce73a8f30055fcb5acaae2cf89117afd484 100644 (file)
 
 #include <ctype.h>
 
+#include "git2/sys/midx.h"
+
 #include "map.h"
 #include "mwindow.h"
+#include "odb.h"
 
 /*
  * A multi-pack-index file.
@@ -49,6 +52,9 @@ typedef struct git_midx_file {
 
        /* The trailer of the file. Contains the SHA1-checksum of the whole file. */
        git_oid checksum;
+
+       /* something like ".git/objects/pack/multi-pack-index". */
+       git_buf filename;
 } git_midx_file;
 
 /*
@@ -63,15 +69,36 @@ typedef struct git_midx_entry {
        git_oid sha1;
 } git_midx_entry;
 
+/*
+ * A writer for `multi-pack-index` files.
+ */
+struct git_midx_writer {
+       /*
+        * The path of the directory where the .pack/.idx files are stored. The
+        * `multi-pack-index` file will be written to the same directory.
+        */
+       git_buf pack_dir;
+
+       /* The list of `git_pack_file`s. */
+       git_vector packs;
+};
+
 int git_midx_open(
                git_midx_file **idx_out,
                const char *path);
+bool git_midx_needs_refresh(
+               const git_midx_file *idx,
+               const char *path);
 int git_midx_entry_find(
                git_midx_entry *e,
                git_midx_file *idx,
                const git_oid *short_oid,
                size_t len);
-void git_midx_close(git_midx_file *idx);
+int git_midx_foreach_entry(
+               git_midx_file *idx,
+               git_odb_foreach_cb cb,
+               void *data);
+int git_midx_close(git_midx_file *idx);
 void git_midx_free(git_midx_file *idx);
 
 /* This is exposed for use in the fuzzers. */
index ac26452f4ebc59a5759ad857d9fcfa2252cd292b..da2dae2b9d6869a145ec12c77fec445d146c1465 100644 (file)
@@ -10,7 +10,7 @@
 #include "vector.h"
 #include "futils.h"
 #include "map.h"
-#include "global.h"
+#include "runtime.h"
 #include "strmap.h"
 #include "pack.h"
 
@@ -20,7 +20,7 @@
                : 32 * 1024 * 1024)
 
 #define DEFAULT_MAPPED_LIMIT \
-       ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
+       ((1024 * 1024) * (sizeof(void*) >= 8 ? UINT64_C(8192) : UINT64_C(256)))
 
 /* default is unlimited */
 #define DEFAULT_FILE_LIMIT 0
@@ -29,26 +29,36 @@ size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE;
 size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT;
 size_t git_mwindow__file_limit = DEFAULT_FILE_LIMIT;
 
-/* Whenever you want to read or modify this, grab git__mwindow_mutex */
+/* Mutex to control access to `git_mwindow__mem_ctl` and `git__pack_cache`. */
+git_mutex git__mwindow_mutex;
+
+/* Whenever you want to read or modify this, grab `git__mwindow_mutex` */
 git_mwindow_ctl git_mwindow__mem_ctl;
 
 /* Global list of mwindow files, to open packs once across repos */
 git_strmap *git__pack_cache = NULL;
 
-static void git_mwindow_files_free(void)
+static void git_mwindow_global_shutdown(void)
 {
        git_strmap *tmp = git__pack_cache;
 
+       git_mutex_free(&git__mwindow_mutex);
+
        git__pack_cache = NULL;
        git_strmap_free(tmp);
 }
 
 int git_mwindow_global_init(void)
 {
-       assert(!git__pack_cache);
+       int error;
+
+       GIT_ASSERT(!git__pack_cache);
 
-       git__on_shutdown(git_mwindow_files_free);
-       return git_strmap_new(&git__pack_cache);
+       if ((error = git_mutex_init(&git__mwindow_mutex)) < 0 ||
+           (error = git_strmap_new(&git__pack_cache)) < 0)
+           return error;
+
+       return git_runtime_shutdown_register(git_mwindow_global_shutdown);
 }
 
 int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
@@ -69,7 +79,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
        git__free(packname);
 
        if (pack != NULL) {
-               git_atomic_inc(&pack->refcount);
+               git_atomic32_inc(&pack->refcount);
                git_mutex_unlock(&git__mwindow_mutex);
                *out = pack;
                return 0;
@@ -81,60 +91,49 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
                return error;
        }
 
-       git_atomic_inc(&pack->refcount);
+       git_atomic32_inc(&pack->refcount);
 
        error = git_strmap_set(git__pack_cache, pack->pack_name, pack);
        git_mutex_unlock(&git__mwindow_mutex);
-
        if (error < 0) {
-               git_packfile_free(pack);
-               return -1;
+               git_packfile_free(pack, false);
+               return error;
        }
 
        *out = pack;
        return 0;
 }
 
-void git_mwindow_put_pack(struct git_pack_file *pack)
+int git_mwindow_put_pack(struct git_pack_file *pack)
 {
-       int count;
+       int count, error;
+       struct git_pack_file *pack_to_delete = NULL;
 
-       if (git_mutex_lock(&git__mwindow_mutex) < 0)
-               return;
+       if ((error = git_mutex_lock(&git__mwindow_mutex)) < 0)
+               return error;
 
        /* put before get would be a corrupted state */
-       assert(git__pack_cache);
+       GIT_ASSERT(git__pack_cache);
 
        /* if we cannot find it, the state is corrupted */
-       assert(git_strmap_exists(git__pack_cache, pack->pack_name));
+       GIT_ASSERT(git_strmap_exists(git__pack_cache, pack->pack_name));
 
-       count = git_atomic_dec(&pack->refcount);
+       count = git_atomic32_dec(&pack->refcount);
        if (count == 0) {
                git_strmap_delete(git__pack_cache, pack->pack_name);
-               git_packfile_free(pack);
+               pack_to_delete = pack;
        }
-
        git_mutex_unlock(&git__mwindow_mutex);
-       return;
-}
+       git_packfile_free(pack_to_delete, false);
 
-void git_mwindow_free_all(git_mwindow_file *mwf)
-{
-       if (git_mutex_lock(&git__mwindow_mutex)) {
-               git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex");
-               return;
-       }
-
-       git_mwindow_free_all_locked(mwf);
-
-       git_mutex_unlock(&git__mwindow_mutex);
+       return 0;
 }
 
 /*
  * Free all the windows in a sequence, typically because we're done
- * with the file
+ * with the file. Needs to hold the git__mwindow_mutex.
  */
-void git_mwindow_free_all_locked(git_mwindow_file *mwf)
+static int git_mwindow_free_all_locked(git_mwindow_file *mwf)
 {
        git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
        size_t i;
@@ -156,7 +155,7 @@ void git_mwindow_free_all_locked(git_mwindow_file *mwf)
 
        while (mwf->windows) {
                git_mwindow *w = mwf->windows;
-               assert(w->inuse_cnt == 0);
+               GIT_ASSERT(w->inuse_cnt == 0);
 
                ctl->mapped -= w->window_map.len;
                ctl->open_windows--;
@@ -166,6 +165,24 @@ void git_mwindow_free_all_locked(git_mwindow_file *mwf)
                mwf->windows = w->next;
                git__free(w);
        }
+
+       return 0;
+}
+
+int git_mwindow_free_all(git_mwindow_file *mwf)
+{
+       int error;
+
+       if (git_mutex_lock(&git__mwindow_mutex)) {
+               git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex");
+               return -1;
+       }
+
+       error = git_mwindow_free_all_locked(mwf);
+
+       git_mutex_unlock(&git__mwindow_mutex);
+
+       return error;
 }
 
 /*
@@ -200,8 +217,8 @@ static bool git_mwindow_scan_recently_used(
        git_mwindow *lru_window = NULL, *lru_last = NULL;
        bool found = false;
 
-       assert(mwf);
-       assert(out_window);
+       GIT_ASSERT_ARG(mwf);
+       GIT_ASSERT_ARG(out_window);
 
        lru_window = *out_window;
        if (out_last)
@@ -240,9 +257,9 @@ static bool git_mwindow_scan_recently_used(
 
 /*
  * Close the least recently used window (that is currently not being used) out
- * of all the files. Called under lock from new_window.
+ * of all the files. Called under lock from new_window_locked.
  */
-static int git_mwindow_close_lru_window(void)
+static int git_mwindow_close_lru_window_locked(void)
 {
        git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
        git_mwindow_file *cur;
@@ -276,13 +293,13 @@ static int git_mwindow_close_lru_window(void)
 }
 
 /*
- * Close the file that does not have any open windows AND whose
+ * Finds the file that does not have any open windows AND whose
  * most-recently-used window is the least-recently used one across all
  * currently open files.
  *
- * Called under lock from new_window.
+ * Called under lock from new_window_locked.
  */
-static int git_mwindow_close_lru_file(void)
+static int git_mwindow_find_lru_file_locked(git_mwindow_file **out)
 {
        git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
        git_mwindow_file *lru_file = NULL, *current_file = NULL;
@@ -295,8 +312,10 @@ static int git_mwindow_close_lru_file(void)
                                current_file, &mru_window, NULL, true, GIT_MWINDOW__MRU)) {
                        continue;
                }
-               if (!lru_window || lru_window->last_used > mru_window->last_used)
+               if (!lru_window || lru_window->last_used > mru_window->last_used) {
+                       lru_window = mru_window;
                        lru_file = current_file;
+               }
        }
 
        if (!lru_file) {
@@ -304,15 +323,12 @@ static int git_mwindow_close_lru_file(void)
                return -1;
        }
 
-       git_mwindow_free_all_locked(lru_file);
-       p_close(lru_file->fd);
-       lru_file->fd = -1;
-
+       *out = lru_file;
        return 0;
 }
 
 /* This gets called under lock from git_mwindow_open */
-static git_mwindow *new_window(
+static git_mwindow *new_window_locked(
        git_file fd,
        off64_t size,
        off64_t offset)
@@ -322,12 +338,11 @@ static git_mwindow *new_window(
        off64_t len;
        git_mwindow *w;
 
-       w = git__malloc(sizeof(*w));
+       w = git__calloc(1, sizeof(*w));
 
        if (w == NULL)
                return NULL;
 
-       memset(w, 0x0, sizeof(*w));
        w->offset = (offset / walign) * walign;
 
        len = size - w->offset;
@@ -337,7 +352,7 @@ static git_mwindow *new_window(
        ctl->mapped += (size_t)len;
 
        while (git_mwindow__mapped_limit < ctl->mapped &&
-                       git_mwindow_close_lru_window() == 0) /* nop */;
+                       git_mwindow_close_lru_window_locked() == 0) /* nop */;
 
        /*
         * We treat `mapped_limit` as a soft limit. If we can't find a
@@ -351,7 +366,7 @@ static git_mwindow *new_window(
                 * we're below our soft limits, so free up what we can and try again.
                 */
 
-               while (git_mwindow_close_lru_window() == 0)
+               while (git_mwindow_close_lru_window_locked() == 0)
                        /* nop */;
 
                if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) {
@@ -407,7 +422,7 @@ unsigned char *git_mwindow_open(
                 * one.
                 */
                if (!w) {
-                       w = new_window(mwf->fd, mwf->size, offset);
+                       w = new_window_locked(mwf->fd, mwf->size, offset);
                        if (w == NULL) {
                                git_mutex_unlock(&git__mwindow_mutex);
                                return NULL;
@@ -435,8 +450,11 @@ unsigned char *git_mwindow_open(
 
 int git_mwindow_file_register(git_mwindow_file *mwf)
 {
+       git_vector closed_files = GIT_VECTOR_INIT;
        git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
-       int ret;
+       int error;
+       size_t i;
+       git_mwindow_file *closed_file = NULL;
 
        if (git_mutex_lock(&git__mwindow_mutex)) {
                git_error_set(GIT_ERROR_THREAD, "unable to lock mwindow mutex");
@@ -444,20 +462,48 @@ int git_mwindow_file_register(git_mwindow_file *mwf)
        }
 
        if (ctl->windowfiles.length == 0 &&
-           git_vector_init(&ctl->windowfiles, 8, NULL) < 0) {
+           (error = git_vector_init(&ctl->windowfiles, 8, NULL)) < 0) {
                git_mutex_unlock(&git__mwindow_mutex);
-               return -1;
+               goto cleanup;
        }
 
        if (git_mwindow__file_limit) {
+               git_mwindow_file *lru_file;
                while (git_mwindow__file_limit <= ctl->windowfiles.length &&
-                               git_mwindow_close_lru_file() == 0) /* nop */;
+                               git_mwindow_find_lru_file_locked(&lru_file) == 0) {
+                       if ((error = git_vector_insert(&closed_files, lru_file)) < 0) {
+                               /*
+                                * Exceeding the file limit seems preferrable to being open to
+                                * data races that can end up corrupting the heap.
+                                */
+                               break;
+                       }
+                       git_mwindow_free_all_locked(lru_file);
+               }
        }
 
-       ret = git_vector_insert(&ctl->windowfiles, mwf);
+       error = git_vector_insert(&ctl->windowfiles, mwf);
        git_mutex_unlock(&git__mwindow_mutex);
+       if (error < 0)
+               goto cleanup;
+
+       /*
+        * Once we have released the global windowfiles lock, we can close each
+        * individual file. Before doing so, acquire that file's lock to avoid
+        * closing a file that is currently being used.
+        */
+       git_vector_foreach(&closed_files, i, closed_file) {
+               error = git_mutex_lock(&closed_file->lock);
+               if (error < 0)
+                       continue;
+               p_close(closed_file->fd);
+               closed_file->fd = -1;
+               git_mutex_unlock(&closed_file->lock);
+       }
 
-       return ret;
+cleanup:
+       git_vector_free(&closed_files);
+       return error;
 }
 
 void git_mwindow_file_deregister(git_mwindow_file *mwf)
index 1a391b055dca96ab926ed5e167dbe1017e865a4f..e3a03f019bd0245f8bd5bb7c5ba188f0003dfce7 100644 (file)
@@ -22,6 +22,7 @@ typedef struct git_mwindow {
 } git_mwindow;
 
 typedef struct git_mwindow_file {
+       git_mutex lock; /* protects updates to fd */
        git_mwindow *windows;
        int fd;
        off64_t size;
@@ -38,8 +39,7 @@ typedef struct git_mwindow_ctl {
 } git_mwindow_ctl;
 
 int git_mwindow_contains(git_mwindow *win, off64_t offset);
-void git_mwindow_free_all(git_mwindow_file *mwf); /* locks */
-void git_mwindow_free_all_locked(git_mwindow_file *mwf); /* run under lock */
+int git_mwindow_free_all(git_mwindow_file *mwf); /* locks */
 unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, off64_t offset, size_t extra, unsigned int *left);
 int git_mwindow_file_register(git_mwindow_file *mwf);
 void git_mwindow_file_deregister(git_mwindow_file *mwf);
@@ -49,6 +49,6 @@ extern int git_mwindow_global_init(void);
 
 struct git_pack_file; /* just declaration to avoid cyclical includes */
 int git_mwindow_get_pack(struct git_pack_file **out, const char *path);
-void git_mwindow_put_pack(struct git_pack_file *pack);
+int git_mwindow_put_pack(struct git_pack_file *pack);
 
 #endif
index dbde626b52b56525747d34572a444572a94f7d99..361e40e7b05f5577f5ef93efd04ba0afe462acd4 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -14,7 +14,7 @@
 #include "posix.h"
 #include "buffer.h"
 #include "http_parser.h"
-#include "global.h"
+#include "runtime.h"
 
 #define DEFAULT_PORT_HTTP  "80"
 #define DEFAULT_PORT_HTTPS "443"
@@ -35,6 +35,46 @@ static const char *default_port_for_scheme(const char *scheme)
        return NULL;
 }
 
+int git_net_url_dup(git_net_url *out, git_net_url *in)
+{
+       if (in->scheme) {
+               out->scheme = git__strdup(in->scheme);
+               GIT_ERROR_CHECK_ALLOC(out->scheme);
+       }
+
+       if (in->host) {
+               out->host = git__strdup(in->host);
+               GIT_ERROR_CHECK_ALLOC(out->host);
+       }
+
+       if (in->port) {
+               out->port = git__strdup(in->port);
+               GIT_ERROR_CHECK_ALLOC(out->port);
+       }
+
+       if (in->path) {
+               out->path = git__strdup(in->path);
+               GIT_ERROR_CHECK_ALLOC(out->path);
+       }
+
+       if (in->query) {
+               out->query = git__strdup(in->query);
+               GIT_ERROR_CHECK_ALLOC(out->query);
+       }
+
+       if (in->username) {
+               out->username = git__strdup(in->username);
+               GIT_ERROR_CHECK_ALLOC(out->username);
+       }
+
+       if (in->password) {
+               out->password = git__strdup(in->password);
+               GIT_ERROR_CHECK_ALLOC(out->password);
+       }
+
+       return 0;
+}
+
 int git_net_url_parse(git_net_url *url, const char *given)
 {
        struct http_parser_url u = {0};
@@ -281,7 +321,8 @@ int git_net_url_apply_redirect(
        git_net_url tmp = GIT_NET_URL_INIT;
        int error = 0;
 
-       assert(url && redirect_location);
+       GIT_ASSERT(url);
+       GIT_ASSERT(redirect_location);
 
        if (redirect_location[0] == '/') {
                git__free(url->path);
@@ -334,7 +375,7 @@ bool git_net_url_valid(git_net_url *url)
        return (url->host && url->port && url->path);
 }
 
-int git_net_url_is_default_port(git_net_url *url)
+bool git_net_url_is_default_port(git_net_url *url)
 {
        const char *default_port;
 
@@ -344,6 +385,11 @@ int git_net_url_is_default_port(git_net_url *url)
                return false;
 }
 
+bool git_net_url_is_ipv6(git_net_url *url)
+{
+       return (strchr(url->host, ':') != NULL);
+}
+
 void git_net_url_swap(git_net_url *a, git_net_url *b)
 {
        git_net_url tmp = GIT_NET_URL_INIT;
@@ -355,6 +401,10 @@ void git_net_url_swap(git_net_url *a, git_net_url *b)
 
 int git_net_url_fmt(git_buf *buf, git_net_url *url)
 {
+       GIT_ASSERT_ARG(url);
+       GIT_ASSERT_ARG(url->scheme);
+       GIT_ASSERT_ARG(url->host);
+
        git_buf_puts(buf, url->scheme);
        git_buf_puts(buf, "://");
 
@@ -398,6 +448,80 @@ int git_net_url_fmt_path(git_buf *buf, git_net_url *url)
        return git_buf_oom(buf) ? -1 : 0;
 }
 
+static bool matches_pattern(
+       git_net_url *url,
+       const char *pattern,
+       size_t pattern_len)
+{
+       const char *domain, *port = NULL, *colon;
+       size_t host_len, domain_len, port_len = 0, wildcard = 0;
+
+       GIT_UNUSED(url);
+       GIT_UNUSED(pattern);
+
+       if (!pattern_len)
+               return false;
+       else if (pattern_len == 1 && pattern[0] == '*')
+               return true;
+       else if (pattern_len > 1 && pattern[0] == '*' && pattern[1] == '.')
+               wildcard = 2;
+       else if (pattern[0] == '.')
+               wildcard = 1;
+
+       domain = pattern + wildcard;
+       domain_len = pattern_len - wildcard;
+
+       if ((colon = memchr(domain, ':', domain_len)) != NULL) {
+               domain_len = colon - domain;
+               port = colon + 1;
+               port_len = pattern_len - wildcard - domain_len - 1;
+       }
+
+       /* A pattern's port *must* match if it's specified */
+       if (port_len && git__strlcmp(url->port, port, port_len) != 0)
+               return false;
+
+       /* No wildcard?  Host must match exactly. */
+       if (!wildcard)
+               return !git__strlcmp(url->host, domain, domain_len);
+
+       /* Wildcard: ensure there's (at least) a suffix match */
+       if ((host_len = strlen(url->host)) < domain_len ||
+           memcmp(url->host + (host_len - domain_len), domain, domain_len))
+               return false;
+
+       /* The pattern is *.domain and the host is simply domain */
+       if (host_len == domain_len)
+               return true;
+
+       /* The pattern is *.domain and the host is foo.domain */
+       return (url->host[host_len - domain_len - 1] == '.');
+}
+
+bool git_net_url_matches_pattern(git_net_url *url, const char *pattern)
+{
+       return matches_pattern(url, pattern, strlen(pattern));
+}
+
+bool git_net_url_matches_pattern_list(
+       git_net_url *url,
+       const char *pattern_list)
+{
+       const char *pattern, *pattern_end, *sep;
+
+       for (pattern = pattern_list;
+            pattern && *pattern;
+            pattern = sep ? sep + 1 : NULL) {
+               sep = strchr(pattern, ',');
+               pattern_end = sep ? sep : strchr(pattern, '\0');
+
+               if (matches_pattern(url, pattern, (pattern_end - pattern)))
+                       return true;
+       }
+
+       return false;
+}
+
 void git_net_url_dispose(git_net_url *url)
 {
        if (url->username)
index 7e72db13f33dffcb4e8808d83d7c6f6a82087c15..322d0bda908a7cf68329120a59410b8b3d60204f 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -21,6 +21,9 @@ typedef struct git_net_url {
 
 #define GIT_NET_URL_INIT { NULL }
 
+/** Duplicate a URL */
+extern int git_net_url_dup(git_net_url *out, git_net_url *in);
+
 /** Parses a string containing a URL into a structure.  */
 extern int git_net_url_parse(git_net_url *url, const char *str);
 
@@ -33,8 +36,11 @@ extern int git_net_url_joinpath(
 /** Ensures that a URL is minimally valid (contains a host, port and path) */
 extern bool git_net_url_valid(git_net_url *url);
 
-/** Returns nonzero if the URL is on the default port. */
-extern int git_net_url_is_default_port(git_net_url *url);
+/** Returns true if the URL is on the default port. */
+extern bool git_net_url_is_default_port(git_net_url *url);
+
+/** Returns true if the host portion of the URL is an ipv6 address. */
+extern bool git_net_url_is_ipv6(git_net_url *url);
 
 /* Applies a redirect to the URL with a git-aware service suffix. */
 extern int git_net_url_apply_redirect(
@@ -51,6 +57,14 @@ extern int git_net_url_fmt(git_buf *out, git_net_url *url);
 /** Place the path and query string into the given buffer. */
 extern int git_net_url_fmt_path(git_buf *buf, git_net_url *url);
 
+/** Determines if the url matches given pattern or pattern list */
+extern bool git_net_url_matches_pattern(
+       git_net_url *url,
+       const char *pattern);
+extern bool git_net_url_matches_pattern_list(
+       git_net_url *url,
+       const char *pattern_list);
+
 /** Disposes the contents of the structure. */
 extern void git_net_url_dispose(git_net_url *url);
 
index 04ae824ccca9af54ba852839eca7eb5e7745bda1..a1ee2927cd9f2b43ab87ee1529fde40d397724ff 100644 (file)
@@ -13,7 +13,7 @@
 #include "posix.h"
 #include "buffer.h"
 #include "http_parser.h"
-#include "global.h"
+#include "runtime.h"
 
 int gitno_recv(gitno_buffer *buf)
 {
@@ -61,18 +61,20 @@ void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data
 }
 
 /* Consume up to ptr and move the rest of the buffer to the beginning */
-void gitno_consume(gitno_buffer *buf, const char *ptr)
+int gitno_consume(gitno_buffer *buf, const char *ptr)
 {
        size_t consumed;
 
-       assert(ptr - buf->data >= 0);
-       assert(ptr - buf->data <= (int) buf->len);
+       GIT_ASSERT(ptr - buf->data >= 0);
+       GIT_ASSERT(ptr - buf->data <= (int) buf->len);
 
        consumed = ptr - buf->data;
 
        memmove(buf->data, ptr, buf->offset - consumed);
        memset(buf->data + buf->offset, 0x0, buf->len - buf->offset);
        buf->offset -= consumed;
+
+       return 0;
 }
 
 /* Consume const bytes and move the rest of the buffer to the beginning */
index 52f1cccb6068cc925e3e2aa9731111bde771da94..7140b39bc45c933d001d333fc7c8046e1c918f7b 100644 (file)
@@ -14,7 +14,7 @@
 #include "net.h"
 
 #ifdef GIT_OPENSSL
-# include <openssl/ssl.h>
+# include "streams/openssl.h"
 #endif
 
 typedef struct gitno_ssl {
@@ -62,7 +62,7 @@ void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data
 void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
 int gitno_recv(gitno_buffer *buf);
 
-void gitno_consume(gitno_buffer *buf, const char *ptr);
+int gitno_consume(gitno_buffer *buf, const char *ptr);
 void gitno_consume_n(gitno_buffer *buf, size_t cons);
 
 #endif
index 68d2ae9ec6263e7509dbd23ba84deb857fdbe4fd..95db334fb83937a059780ee8d8ddcdc6c9e7c560 100644 (file)
@@ -407,31 +407,33 @@ cleanup:
        return error;
 }
 
-static int note_get_default_ref(char **out, git_repository *repo)
+static int note_get_default_ref(git_buf *out, git_repository *repo)
 {
        git_config *cfg;
-       int ret = git_repository_config__weakptr(&cfg, repo);
+       int error;
+
+       if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
+               return error;
 
-       *out = (ret != 0) ? NULL : git_config__get_string_force(
-               cfg, "core.notesref", GIT_NOTES_DEFAULT_REF);
+       error = git_config_get_string_buf(out, cfg, "core.notesref");
 
-       return ret;
+       if (error == GIT_ENOTFOUND)
+               error = git_buf_puts(out, GIT_NOTES_DEFAULT_REF);
+
+       return error;
 }
 
-static int normalize_namespace(char **out, git_repository *repo, const char *notes_ref)
+static int normalize_namespace(git_buf *out, git_repository *repo, const char *notes_ref)
 {
-       if (notes_ref) {
-               *out = git__strdup(notes_ref);
-               GIT_ERROR_CHECK_ALLOC(*out);
-               return 0;
-       }
+       if (notes_ref)
+               return git_buf_puts(out, notes_ref);
 
        return note_get_default_ref(out, repo);
 }
 
 static int retrieve_note_commit(
        git_commit **commit_out,
-       char **notes_ref_out,
+       git_buf *notes_ref_out,
        git_repository *repo,
        const char *notes_ref)
 {
@@ -441,7 +443,7 @@ static int retrieve_note_commit(
        if ((error = normalize_namespace(notes_ref_out, repo, notes_ref)) < 0)
                return error;
 
-       if ((error = git_reference_name_to_id(&oid, repo, *notes_ref_out)) < 0)
+       if ((error = git_reference_name_to_id(&oid, repo, notes_ref_out->ptr)) < 0)
                return error;
 
        if (git_commit_lookup(commit_out, repo, &oid) < 0)
@@ -476,7 +478,7 @@ int git_note_read(git_note **out, git_repository *repo,
                  const char *notes_ref_in, const git_oid *oid)
 {
        int error;
-       char *notes_ref = NULL;
+       git_buf notes_ref = GIT_BUF_INIT;
        git_commit *commit = NULL;
 
        error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
@@ -487,7 +489,7 @@ int git_note_read(git_note **out, git_repository *repo,
        error = git_note_commit_read(out, repo, commit, oid);
 
 cleanup:
-       git__free(notes_ref);
+       git_buf_dispose(&notes_ref);
        git_commit_free(commit);
        return error;
 }
@@ -534,7 +536,7 @@ int git_note_create(
        int allow_note_overwrite)
 {
        int error;
-       char *notes_ref = NULL;
+       git_buf notes_ref = GIT_BUF_INIT;
        git_commit *existing_notes_commit = NULL;
        git_reference *ref = NULL;
        git_oid notes_blob_oid, notes_commit_oid;
@@ -553,14 +555,14 @@ int git_note_create(
        if (error < 0)
                goto cleanup;
 
-       error = git_reference_create(&ref, repo, notes_ref,
+       error = git_reference_create(&ref, repo, notes_ref.ptr,
                                &notes_commit_oid, 1, NULL);
 
        if (out != NULL)
                git_oid_cpy(out, &notes_blob_oid);
 
 cleanup:
-       git__free(notes_ref);
+       git_buf_dispose(&notes_ref);
        git_commit_free(existing_notes_commit);
        git_reference_free(ref);
        return error;
@@ -596,7 +598,7 @@ int git_note_remove(git_repository *repo, const char *notes_ref_in,
                const git_oid *oid)
 {
        int error;
-       char *notes_ref_target = NULL;
+       git_buf notes_ref_target = GIT_BUF_INIT;
        git_commit *existing_notes_commit = NULL;
        git_oid new_notes_commit;
        git_reference *notes_ref = NULL;
@@ -612,11 +614,11 @@ int git_note_remove(git_repository *repo, const char *notes_ref_in,
        if (error < 0)
                goto cleanup;
 
-       error = git_reference_create(&notes_ref, repo, notes_ref_target,
+       error = git_reference_create(&notes_ref, repo, notes_ref_target.ptr,
                        &new_notes_commit, 1, NULL);
 
 cleanup:
-       git__free(notes_ref_target);
+       git_buf_dispose(&notes_ref_target);
        git_reference_free(notes_ref);
        git_commit_free(existing_notes_commit);
        return error;
@@ -624,41 +626,39 @@ cleanup:
 
 int git_note_default_ref(git_buf *out, git_repository *repo)
 {
-       char *default_ref;
        int error;
 
-       assert(out && repo);
-
-       git_buf_sanitize(out);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
-       if ((error = note_get_default_ref(&default_ref, repo)) < 0)
-               return error;
+       if ((error = git_buf_sanitize(out)) < 0 ||
+           (error = note_get_default_ref(out, repo)) < 0)
+               git_buf_dispose(out);
 
-       git_buf_attach(out, default_ref, strlen(default_ref));
-       return 0;
+       return error;
 }
 
 const git_signature *git_note_committer(const git_note *note)
 {
-       assert(note);
+       GIT_ASSERT_ARG_WITH_RETVAL(note, NULL);
        return note->committer;
 }
 
 const git_signature *git_note_author(const git_note *note)
 {
-       assert(note);
+       GIT_ASSERT_ARG_WITH_RETVAL(note, NULL);
        return note->author;
 }
 
-const char * git_note_message(const git_note *note)
+const char *git_note_message(const git_note *note)
 {
-       assert(note);
+       GIT_ASSERT_ARG_WITH_RETVAL(note, NULL);
        return note->message;
 }
 
-const git_oid * git_note_id(const git_note *note)
+const git_oid *git_note_id(const git_note *note)
 {
-       assert(note);
+       GIT_ASSERT_ARG_WITH_RETVAL(note, NULL);
        return &note->id;
 }
 
@@ -674,7 +674,7 @@ void git_note_free(git_note *note)
 }
 
 static int process_entry_path(
-       const charentry_path,
+       const char *entry_path,
        git_oid *annotated_object_id)
 {
        int error = 0;
@@ -780,7 +780,7 @@ int git_note_iterator_new(
 {
        int error;
        git_commit *commit = NULL;
-       char *notes_ref;
+       git_buf notes_ref = GIT_BUF_INIT;
 
        error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
        if (error < 0)
@@ -789,15 +789,15 @@ int git_note_iterator_new(
        error = git_note_commit_iterator_new(it, commit);
 
 cleanup:
-       git__free(notes_ref);
+       git_buf_dispose(&notes_ref);
        git_commit_free(commit);
 
        return error;
 }
 
 int git_note_next(
-       git_oidnote_id,
-       git_oidannotated_id,
+       git_oid *note_id,
+       git_oid *annotated_id,
        git_note_iterator *it)
 {
        int error;
index 749b0caf24262b7b6640d5b56b3cadbeade525fb..42e1e46bcc515f143eeba9279a366e5790feac80 100644 (file)
@@ -67,7 +67,7 @@ int git_object__from_raw(
        size_t object_size;
        int error;
 
-       assert(object_out);
+       GIT_ASSERT_ARG(object_out);
        *object_out = NULL;
 
        /* Validate type match */
@@ -91,7 +91,7 @@ int git_object__from_raw(
 
        /* Parse raw object data */
        def = &git_objects_table[type];
-       assert(def->free && def->parse_raw);
+       GIT_ASSERT(def->free && def->parse_raw);
 
        if ((error = def->parse_raw(object, data, size)) < 0) {
                def->free(object);
@@ -115,7 +115,7 @@ int git_object__from_odb_object(
        git_object_def *def;
        git_object *object = NULL;
 
-       assert(object_out);
+       GIT_ASSERT_ARG(object_out);
        *object_out = NULL;
 
        /* Validate type match */
@@ -141,7 +141,7 @@ int git_object__from_odb_object(
 
        /* Parse raw object data */
        def = &git_objects_table[odb_obj->cached.type];
-       assert(def->free && def->parse);
+       GIT_ASSERT(def->free && def->parse);
 
        if ((error = def->parse(object, odb_obj)) < 0)
                def->free(object);
@@ -174,7 +174,9 @@ int git_object_lookup_prefix(
        git_odb_object *odb_obj = NULL;
        int error = 0;
 
-       assert(repo && object_out && id);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(object_out);
+       GIT_ASSERT_ARG(id);
 
        if (len < GIT_OID_MINPREFIXLEN) {
                git_error_set(GIT_ERROR_OBJECT, "ambiguous lookup - OID prefix is too short");
@@ -211,7 +213,7 @@ int git_object_lookup_prefix(
                        } else if (cached->flags == GIT_CACHE_STORE_RAW) {
                                odb_obj = (git_odb_object *)cached;
                        } else {
-                               assert(!"Wrong caching type in the global object cache");
+                               GIT_ASSERT(!"Wrong caching type in the global object cache");
                        }
                } else {
                        /* Object was not found in the cache, let's explore the backends.
@@ -263,19 +265,19 @@ void git_object_free(git_object *object)
 
 const git_oid *git_object_id(const git_object *obj)
 {
-       assert(obj);
+       GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
        return &obj->cached.oid;
 }
 
 git_object_t git_object_type(const git_object *obj)
 {
-       assert(obj);
+       GIT_ASSERT_ARG_WITH_RETVAL(obj, GIT_OBJECT_INVALID);
        return obj->cached.type;
 }
 
 git_repository *git_object_owner(const git_object *obj)
 {
-       assert(obj);
+       GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
        return obj->repo;
 }
 
@@ -396,9 +398,10 @@ int git_object_peel(
        git_object *source, *deref = NULL;
        int error;
 
-       assert(object && peeled);
+       GIT_ASSERT_ARG(object);
+       GIT_ASSERT_ARG(peeled);
 
-       assert(target_type == GIT_OBJECT_TAG ||
+       GIT_ASSERT_ARG(target_type == GIT_OBJECT_TAG ||
                target_type == GIT_OBJECT_COMMIT ||
                target_type == GIT_OBJECT_TREE ||
                target_type == GIT_OBJECT_BLOB ||
@@ -461,7 +464,9 @@ int git_object_lookup_bypath(
        git_tree *tree = NULL;
        git_tree_entry *entry = NULL;
 
-       assert(out && treeish && path);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(treeish);
+       GIT_ASSERT_ARG(path);
 
        if ((error = git_object_peel((git_object**)&tree, treeish, GIT_OBJECT_TREE)) < 0 ||
                 (error = git_tree_entry_bypath(&entry, tree, path)) < 0)
@@ -493,9 +498,12 @@ int git_object_short_id(git_buf *out, const git_object *obj)
        git_oid id = {{0}};
        git_odb *odb;
 
-       assert(out && obj);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(obj);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
-       git_buf_sanitize(out);
        repo = git_object_owner(obj);
 
        if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0)
index 129a63255dc4424f869d6dc7a4907e22fb835fd4..7834e5f15cff9c9bc487efc03b5d061b0dc390c1 100644 (file)
--- a/src/odb.c
+++ b/src/odb.c
 
 #define GIT_ALTERNATES_FILE "info/alternates"
 
+#define GIT_ALTERNATES_MAX_DEPTH 5
+
 /*
  * We work under the assumption that most objects for long-running
  * operations will be packed
  */
-#define GIT_LOOSE_PRIORITY 1
-#define GIT_PACKED_PRIORITY 2
-
-#define GIT_ALTERNATES_MAX_DEPTH 5
+int git_odb__loose_priority = GIT_ODB_DEFAULT_LOOSE_PRIORITY;
+int git_odb__packed_priority = GIT_ODB_DEFAULT_PACKED_PRIORITY;
 
 bool git_odb__strict_hash_verification = true;
 
@@ -114,7 +114,8 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj)
        size_t hdrlen;
        int error;
 
-       assert(id && obj);
+       GIT_ASSERT_ARG(id);
+       GIT_ASSERT_ARG(obj);
 
        if (!git_object_typeisloose(obj->type)) {
                git_error_set(GIT_ERROR_INVALID, "invalid object type");
@@ -259,9 +260,7 @@ int git_odb__hashfd_filtered(
        if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) {
                git_buf post = GIT_BUF_INIT;
 
-               error = git_filter_list_apply_to_data(&post, fl, &raw);
-
-               git_buf_dispose(&raw);
+               error = git_filter_list__convert_buf(&post, fl, &raw);
 
                if (!error)
                        error = git_odb_hash(out, post.ptr, post.size, type);
@@ -298,14 +297,15 @@ int git_odb__hashlink(git_oid *out, const char *path)
                GIT_ERROR_CHECK_ALLOC(link_data);
 
                read_len = p_readlink(path, link_data, size);
-               link_data[size] = '\0';
-               if (read_len != size) {
+               if (read_len == -1) {
                        git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path);
                        git__free(link_data);
                        return -1;
                }
+               GIT_ASSERT(read_len <= size);
+               link_data[read_len] = '\0';
 
-               result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB);
+               result = git_odb_hash(out, link_data, read_len, GIT_OBJECT_BLOB);
                git__free(link_data);
        } else {
                int fd = git_futils_open_ro(path);
@@ -346,7 +346,7 @@ int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
 {
        git_rawobj raw;
 
-       assert(id);
+       GIT_ASSERT_ARG(id);
 
        raw.data = (void *)data;
        raw.len = len;
@@ -376,7 +376,7 @@ static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t
 {
        fake_wstream *stream = (fake_wstream *)_stream;
 
-       assert(stream->written + len <= stream->size);
+       GIT_ASSERT(stream->written + len <= stream->size);
 
        memcpy(stream->buffer + stream->written, data, len);
        stream->written += len;
@@ -449,12 +449,18 @@ int git_odb_new(git_odb **out)
        git_odb *db = git__calloc(1, sizeof(*db));
        GIT_ERROR_CHECK_ALLOC(db);
 
+       if (git_mutex_init(&db->lock) < 0) {
+               git__free(db);
+               return -1;
+       }
        if (git_cache_init(&db->own_cache) < 0) {
+               git_mutex_free(&db->lock);
                git__free(db);
                return -1;
        }
        if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
                git_cache_dispose(&db->own_cache);
+               git_mutex_free(&db->lock);
                git__free(db);
                return -1;
        }
@@ -470,12 +476,13 @@ static int add_backend_internal(
 {
        backend_internal *internal;
 
-       assert(odb && backend);
+       GIT_ASSERT_ARG(odb);
+       GIT_ASSERT_ARG(backend);
 
        GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend");
 
        /* Check if the backend is already owned by another ODB */
-       assert(!backend->odb || backend->odb == odb);
+       GIT_ASSERT(!backend->odb || backend->odb == odb);
 
        internal = git__malloc(sizeof(backend_internal));
        GIT_ERROR_CHECK_ALLOC(internal);
@@ -485,13 +492,18 @@ static int add_backend_internal(
        internal->is_alternate = is_alternate;
        internal->disk_inode = disk_inode;
 
+       if (git_mutex_lock(&odb->lock) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return -1;
+       }
        if (git_vector_insert(&odb->backends, internal) < 0) {
+               git_mutex_unlock(&odb->lock);
                git__free(internal);
                return -1;
        }
-
        git_vector_sort(&odb->backends);
        internal->backend->odb = odb;
+       git_mutex_unlock(&odb->lock);
        return 0;
 }
 
@@ -507,8 +519,19 @@ int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
 
 size_t git_odb_num_backends(git_odb *odb)
 {
-       assert(odb);
-       return odb->backends.length;
+       size_t length;
+       bool locked = true;
+
+       GIT_ASSERT_ARG(odb);
+
+       if (git_mutex_lock(&odb->lock) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               locked = false;
+       }
+       length = odb->backends.length;
+       if (locked)
+               git_mutex_unlock(&odb->lock);
+       return length;
 }
 
 static int git_odb__error_unsupported_in_backend(const char *action)
@@ -522,24 +545,35 @@ static int git_odb__error_unsupported_in_backend(const char *action)
 int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
 {
        backend_internal *internal;
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(odb);
 
-       assert(out && odb);
+
+       if ((error = git_mutex_lock(&odb->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        internal = git_vector_get(&odb->backends, pos);
 
-       if (internal && internal->backend) {
-               *out = internal->backend;
-               return 0;
+       if (!internal || !internal->backend) {
+               git_mutex_unlock(&odb->lock);
+
+               git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
+               return GIT_ENOTFOUND;
        }
+       *out = internal->backend;
+       git_mutex_unlock(&odb->lock);
 
-       git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
-       return GIT_ENOTFOUND;
+       return 0;
 }
 
 int git_odb__add_default_backends(
        git_odb *db, const char *objects_dir,
        bool as_alternates, int alternate_depth)
 {
-       size_t i;
+       size_t i = 0;
        struct stat st;
        ino_t inode;
        git_odb_backend *loose, *packed;
@@ -548,7 +582,7 @@ int git_odb__add_default_backends(
         * a cross-platform workaround for this */
 #ifdef GIT_WIN32
        GIT_UNUSED(i);
-       GIT_UNUSED(st);
+       GIT_UNUSED(&st);
 
        inode = 0;
 #else
@@ -563,23 +597,40 @@ int git_odb__add_default_backends(
 
        inode = st.st_ino;
 
+       if (git_mutex_lock(&db->lock) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return -1;
+       }
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *backend = git_vector_get(&db->backends, i);
-               if (backend->disk_inode == inode)
+               if (backend->disk_inode == inode) {
+                       git_mutex_unlock(&db->lock);
                        return 0;
+               }
        }
+       git_mutex_unlock(&db->lock);
 #endif
 
        /* add the loose object backend */
        if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
-               add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0)
+               add_backend_internal(db, loose, git_odb__loose_priority, as_alternates, inode) < 0)
                return -1;
 
        /* add the packed file backend */
        if (git_odb_backend_pack(&packed, objects_dir) < 0 ||
-               add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0)
+               add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0)
                return -1;
 
+       if (git_mutex_lock(&db->lock) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return -1;
+       }
+       if (!db->cgraph && git_commit_graph_new(&db->cgraph, objects_dir, false) < 0) {
+               git_mutex_unlock(&db->lock);
+               return -1;
+       }
+       git_mutex_unlock(&db->lock);
+
        return load_alternates(db, objects_dir, alternate_depth);
 }
 
@@ -641,11 +692,29 @@ int git_odb_add_disk_alternate(git_odb *odb, const char *path)
        return git_odb__add_default_backends(odb, path, true, 0);
 }
 
+int git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph)
+{
+       int error = 0;
+
+       GIT_ASSERT_ARG(odb);
+
+       if ((error = git_mutex_lock(&odb->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the db lock");
+               return error;
+       }
+       git_commit_graph_free(odb->cgraph);
+       odb->cgraph = cgraph;
+       git_mutex_unlock(&odb->lock);
+
+       return error;
+}
+
 int git_odb_open(git_odb **out, const char *objects_dir)
 {
        git_odb *db;
 
-       assert(out && objects_dir);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(objects_dir);
 
        *out = NULL;
 
@@ -682,7 +751,12 @@ int git_odb__set_caps(git_odb *odb, int caps)
 static void odb_free(git_odb *db)
 {
        size_t i;
+       bool locked = true;
 
+       if (git_mutex_lock(&db->lock) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               locked = false;
+       }
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *backend = internal->backend;
@@ -691,9 +765,13 @@ static void odb_free(git_odb *db)
 
                git__free(internal);
        }
+       if (locked)
+               git_mutex_unlock(&db->lock);
 
+       git_commit_graph_free(db->cgraph);
        git_vector_free(&db->backends);
        git_cache_dispose(&db->own_cache);
+       git_mutex_free(&db->lock);
 
        git__memzero(db, sizeof(*db));
        git__free(db);
@@ -714,7 +792,12 @@ static int odb_exists_1(
 {
        size_t i;
        bool found = false;
+       int error;
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length && !found; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -725,10 +808,34 @@ static int odb_exists_1(
                if (b->exists != NULL)
                        found = (bool)b->exists(b, id);
        }
+       git_mutex_unlock(&db->lock);
 
        return (int)found;
 }
 
+int git_odb__get_commit_graph_file(git_commit_graph_file **out, git_odb *db)
+{
+       int error = 0;
+       git_commit_graph_file *result = NULL;
+
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the db lock");
+               return error;
+       }
+       if (!db->cgraph) {
+               error = GIT_ENOTFOUND;
+               goto done;
+       }
+       error = git_commit_graph_get_file(&result, db->cgraph);
+       if (error)
+               goto done;
+       *out = result;
+
+done:
+       git_mutex_unlock(&db->lock);
+       return error;
+}
+
 static int odb_freshen_1(
        git_odb *db,
        const git_oid *id,
@@ -736,7 +843,12 @@ static int odb_freshen_1(
 {
        size_t i;
        bool found = false;
+       int error;
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length && !found; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -749,13 +861,15 @@ static int odb_freshen_1(
                else if (b->exists != NULL)
                        found = b->exists(b, id);
        }
+       git_mutex_unlock(&db->lock);
 
        return (int)found;
 }
 
 int git_odb__freshen(git_odb *db, const git_oid *id)
 {
-       assert(db && id);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(id);
 
        if (odb_freshen_1(db, id, false))
                return 1;
@@ -771,7 +885,8 @@ int git_odb_exists(git_odb *db, const git_oid *id)
 {
        git_odb_object *object;
 
-       assert(db && id);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(id);
 
        if (git_oid_is_zero(id))
                return 0;
@@ -798,6 +913,11 @@ static int odb_exists_prefix_1(git_oid *out, git_odb *db,
        int error = GIT_ENOTFOUND, num_found = 0;
        git_oid last_found = {{0}}, found;
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
+       error = GIT_ENOTFOUND;
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -811,18 +931,23 @@ static int odb_exists_prefix_1(git_oid *out, git_odb *db,
                error = b->exists_prefix(&found, b, key, len);
                if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
                        continue;
-               if (error)
+               if (error) {
+                       git_mutex_unlock(&db->lock);
                        return error;
+               }
 
                /* make sure found item doesn't introduce ambiguity */
                if (num_found) {
-                       if (git_oid__cmp(&last_found, &found))
+                       if (git_oid__cmp(&last_found, &found)) {
+                               git_mutex_unlock(&db->lock);
                                return git_odb__error_ambiguous("multiple matches for prefix");
+                       }
                } else {
                        git_oid_cpy(&last_found, &found);
                        num_found++;
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (!num_found)
                return GIT_ENOTFOUND;
@@ -839,7 +964,8 @@ int git_odb_exists_prefix(
        int error;
        git_oid key = {{0}};
 
-       assert(db && short_id);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(short_id);
 
        if (len < GIT_OID_MINPREFIXLEN)
                return git_odb__error_ambiguous("prefix length too short");
@@ -875,7 +1001,8 @@ int git_odb_expand_ids(
 {
        size_t i;
 
-       assert(db && ids);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(ids);
 
        for (i = 0; i < count; i++) {
                git_odb_expand_id *query = &ids[i];
@@ -962,6 +1089,10 @@ static int odb_read_header_1(
                return 0;
        }
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -983,9 +1114,11 @@ static int odb_read_header_1(
                case GIT_ENOTFOUND:
                        break;
                default:
+                       git_mutex_unlock(&db->lock);
                        return error;
                }
        }
+       git_mutex_unlock(&db->lock);
 
        return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND;
 }
@@ -997,7 +1130,11 @@ int git_odb__read_header_or_object(
        int error = GIT_ENOTFOUND;
        git_odb_object *object;
 
-       assert(db && id && out && len_p && type_p);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(id);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(len_p);
+       GIT_ASSERT_ARG(type_p);
 
        *out = NULL;
 
@@ -1054,6 +1191,10 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
                        return error;
        }
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length && !found; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1066,12 +1207,15 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
                        if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
                                continue;
 
-                       if (error < 0)
+                       if (error < 0) {
+                               git_mutex_unlock(&db->lock);
                                return error;
+                       }
 
                        found = true;
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (!found)
                return GIT_ENOTFOUND;
@@ -1104,7 +1248,9 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
 {
        int error;
 
-       assert(out && db && id);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(id);
 
        if (git_oid_is_zero(id))
                return error_null_oid(GIT_ENOTFOUND, "cannot read object");
@@ -1162,6 +1308,10 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
        bool found = false;
        git_odb_object *object;
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1178,8 +1328,10 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
                                continue;
                        }
 
-                       if (error)
+                       if (error) {
+                               git_mutex_unlock(&db->lock);
                                goto out;
+                       }
 
                        git__free(data);
                        data = raw.data;
@@ -1194,6 +1346,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
 
                                error = git_odb__error_ambiguous(buf.ptr);
                                git_buf_dispose(&buf);
+                               git_mutex_unlock(&db->lock);
                                goto out;
                        }
 
@@ -1201,6 +1354,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
                        found = true;
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (!found)
                return GIT_ENOTFOUND;
@@ -1237,7 +1391,8 @@ int git_odb_read_prefix(
        git_oid key = {{0}};
        int error;
 
-       assert(out && db);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(db);
 
        if (len < GIT_OID_MINPREFIXLEN)
                return git_odb__error_ambiguous("prefix length too short");
@@ -1267,16 +1422,32 @@ int git_odb_read_prefix(
 int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload)
 {
        unsigned int i;
+       git_vector backends = GIT_VECTOR_INIT;
        backend_internal *internal;
+       int error = 0;
+
+       /* Make a copy of the backends vector to invoke the callback without holding the lock. */
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               goto cleanup;
+       }
+       error = git_vector_dup(&backends, &db->backends, NULL);
+       git_mutex_unlock(&db->lock);
+
+       if (error < 0)
+               goto cleanup;
 
-       git_vector_foreach(&db->backends, i, internal) {
+       git_vector_foreach(&backends, i, internal) {
                git_odb_backend *b = internal->backend;
-               int error = b->foreach(b, cb, payload);
+               error = b->foreach(b, cb, payload);
                if (error != 0)
-                       return error;
+                       goto cleanup;
        }
 
-       return 0;
+cleanup:
+       git_vector_free(&backends);
+
+       return error;
 }
 
 int git_odb_write(
@@ -1286,7 +1457,8 @@ int git_odb_write(
        int error;
        git_odb_stream *stream;
 
-       assert(oid && db);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(db);
 
        if ((error = git_odb_hash(oid, data, len, type)) < 0)
                return error;
@@ -1297,6 +1469,10 @@ int git_odb_write(
        if (git_odb__freshen(db, oid))
                return 0;
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0, error = GIT_ERROR; i < db->backends.length && error < 0; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1308,6 +1484,7 @@ int git_odb_write(
                if (b->write != NULL)
                        error = b->write(b, oid, data, len, type);
        }
+       git_mutex_unlock(&db->lock);
 
        if (!error || error == GIT_PASSTHROUGH)
                return 0;
@@ -1346,8 +1523,14 @@ int git_odb_open_wstream(
        int error = GIT_ERROR;
        git_hash_ctx *ctx = NULL;
 
-       assert(stream && db);
+       GIT_ASSERT_ARG(stream);
+       GIT_ASSERT_ARG(db);
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
+       error = GIT_ERROR;
        for (i = 0; i < db->backends.length && error < 0; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1364,6 +1547,7 @@ int git_odb_open_wstream(
                        error = init_fake_wstream(stream, b, size, type);
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (error < 0) {
                if (error == GIT_PASSTHROUGH)
@@ -1456,8 +1640,14 @@ int git_odb_open_rstream(
        size_t i, reads = 0;
        int error = GIT_ERROR;
 
-       assert(stream && db);
+       GIT_ASSERT_ARG(stream);
+       GIT_ASSERT_ARG(db);
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
+       error = GIT_ERROR;
        for (i = 0; i < db->backends.length && error < 0; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1467,6 +1657,7 @@ int git_odb_open_rstream(
                        error = b->readstream(stream, len, type, b, oid);
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (error == GIT_PASSTHROUGH)
                error = 0;
@@ -1481,8 +1672,14 @@ int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_
        size_t i, writes = 0;
        int error = GIT_ERROR;
 
-       assert(out && db);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(db);
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
+       error = GIT_ERROR;
        for (i = 0; i < db->backends.length && error < 0; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
@@ -1496,6 +1693,7 @@ int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_
                        error = b->writepack(out, b, db, progress_cb, progress_payload);
                }
        }
+       git_mutex_unlock(&db->lock);
 
        if (error == GIT_PASSTHROUGH)
                error = 0;
@@ -1505,6 +1703,35 @@ int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_
        return error;
 }
 
+int git_odb_write_multi_pack_index(git_odb *db)
+{
+       size_t i, writes = 0;
+       int error = GIT_ERROR;
+
+       GIT_ASSERT_ARG(db);
+
+       for (i = 0; i < db->backends.length && error < 0; ++i) {
+               backend_internal *internal = git_vector_get(&db->backends, i);
+               git_odb_backend *b = internal->backend;
+
+               /* we don't write in alternates! */
+               if (internal->is_alternate)
+                       continue;
+
+               if (b->writemidx != NULL) {
+                       ++writes;
+                       error = b->writemidx(b);
+               }
+       }
+
+       if (error == GIT_PASSTHROUGH)
+               error = 0;
+       if (error < 0 && !writes)
+               error = git_odb__error_unsupported_in_backend("write multi-pack-index");
+
+       return error;
+}
+
 void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
 {
        GIT_UNUSED(backend);
@@ -1527,18 +1754,29 @@ void git_odb_backend_data_free(git_odb_backend *backend, void *data)
 int git_odb_refresh(struct git_odb *db)
 {
        size_t i;
-       assert(db);
+       int error;
+
+       GIT_ASSERT_ARG(db);
 
+       if ((error = git_mutex_lock(&db->lock)) < 0) {
+               git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
+               return error;
+       }
        for (i = 0; i < db->backends.length; ++i) {
                backend_internal *internal = git_vector_get(&db->backends, i);
                git_odb_backend *b = internal->backend;
 
                if (b->refresh != NULL) {
                        int error = b->refresh(b);
-                       if (error < 0)
+                       if (error < 0) {
+                               git_mutex_unlock(&db->lock);
                                return error;
+                       }
                }
        }
+       if (db->cgraph)
+               git_commit_graph_refresh(db->cgraph);
+       git_mutex_unlock(&db->lock);
 
        return 0;
 }
index 8dd4efd64f34266d21dc43d757529f6ee3250e79..4a8ebff191386dd51ee627300e95a397b18a9669 100644 (file)
--- a/src/odb.h
+++ b/src/odb.h
 #include "git2/odb.h"
 #include "git2/oid.h"
 #include "git2/types.h"
+#include "git2/sys/commit_graph.h"
 
-#include "vector.h"
 #include "cache.h"
-#include "posix.h"
+#include "commit_graph.h"
 #include "filter.h"
+#include "posix.h"
+#include "vector.h"
 
 #define GIT_OBJECTS_DIR "objects/"
 #define GIT_OBJECT_DIR_MODE 0777
 #define GIT_OBJECT_FILE_MODE 0444
 
+#define GIT_ODB_DEFAULT_LOOSE_PRIORITY 1
+#define GIT_ODB_DEFAULT_PACKED_PRIORITY 2
+
 extern bool git_odb__strict_hash_verification;
 
 /* DO NOT EXPORT */
@@ -40,8 +45,10 @@ struct git_odb_object {
 /* EXPORT */
 struct git_odb {
        git_refcount rc;
+       git_mutex lock;  /* protects backends */
        git_vector backends;
        git_cache own_cache;
+       git_commit_graph *cgraph;
        unsigned int do_fsync :1;
 };
 
@@ -126,6 +133,13 @@ int git_odb__read_header_or_object(
        git_odb_object **out, size_t *len_p, git_object_t *type_p,
        git_odb *db, const git_oid *id);
 
+/*
+ * Attempt to get the ODB's commit-graph file. This object is still owned by
+ * the ODB. If the repository does not contain a commit-graph, it will return
+ * GIT_ENOTFOUND.
+ */
+int git_odb__get_commit_graph_file(git_commit_graph_file **out, git_odb *odb);
+
 /* freshen an entry in the object database */
 int git_odb__freshen(git_odb *db, const git_oid *id);
 
index 68287795a5404338da0c346ab13e536f43722e41..b0abbbf4c2731372c8c66440a461477c8e56b5e5 100644 (file)
@@ -309,7 +309,7 @@ static int read_loose_standard(git_rawobj *out, git_buf *obj)
                goto done;
        }
 
-       assert(decompressed >= head_len);
+       GIT_ASSERT(decompressed >= head_len);
        body_len = decompressed - head_len;
 
        if (body_len)
@@ -344,7 +344,8 @@ static int read_loose(git_rawobj *out, git_buf *loc)
        int error;
        git_buf obj = GIT_BUF_INIT;
 
-       assert(out && loc);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(loc);
 
        if (git_buf_oom(loc))
                return -1;
@@ -411,7 +412,8 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
        ssize_t obj_len;
        int fd, error;
 
-       assert(out && loc);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(loc);
 
        if (git_buf_oom(loc))
                return -1;
@@ -585,7 +587,8 @@ static int loose_backend__read_header(size_t *len_p, git_object_t *type_p, git_o
        git_rawobj raw;
        int error;
 
-       assert(backend && oid);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(oid);
 
        raw.len = 0;
        raw.type = GIT_OBJECT_INVALID;
@@ -609,7 +612,8 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_object_t *typ
        git_rawobj raw;
        int error = 0;
 
-       assert(backend && oid);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(oid);
 
        if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
                error = git_odb__error_notfound("no matching loose object",
@@ -636,7 +640,7 @@ static int loose_backend__read_prefix(
 {
        int error = 0;
 
-       assert(len >= GIT_OID_MINPREFIXLEN && len <= GIT_OID_HEXSZ);
+       GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN && len <= GIT_OID_HEXSZ);
 
        if (len == GIT_OID_HEXSZ) {
                /* We can fall back to regular read method */
@@ -647,7 +651,7 @@ static int loose_backend__read_prefix(
                git_buf object_path = GIT_BUF_INIT;
                git_rawobj raw;
 
-               assert(backend && short_oid);
+               GIT_ASSERT_ARG(backend && short_oid);
 
                if ((error = locate_object_short_oid(&object_path, out_oid,
                                (loose_backend *)backend, short_oid, len)) == 0 &&
@@ -669,7 +673,8 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
        git_buf object_path = GIT_BUF_INIT;
        int error;
 
-       assert(backend && oid);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(oid);
 
        error = locate_object(&object_path, (loose_backend *)backend, oid);
 
@@ -684,7 +689,10 @@ static int loose_backend__exists_prefix(
        git_buf object_path = GIT_BUF_INIT;
        int error;
 
-       assert(backend && out && short_id && len >= GIT_OID_MINPREFIXLEN);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(short_id);
+       GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN);
 
        error = locate_object_short_oid(
                &object_path, out, (loose_backend *)backend, short_id, len);
@@ -759,7 +767,8 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb
        struct foreach_state state;
        loose_backend *backend = (loose_backend *) _backend;
 
-       assert(backend && cb);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(cb);
 
        objects_dir = backend->objects_dir;
 
@@ -833,7 +842,7 @@ static int loose_backend__writestream(git_odb_stream **stream_out, git_odb_backe
        size_t hdrlen;
        int error;
 
-       assert(_backend);
+       GIT_ASSERT_ARG(_backend);
 
        backend = (loose_backend *)_backend;
        *stream_out = NULL;
@@ -991,7 +1000,11 @@ static int loose_backend__readstream(
        obj_hdr hdr;
        int error = 0;
 
-       assert(stream_out && len_out && type_out && _backend && oid);
+       GIT_ASSERT_ARG(stream_out);
+       GIT_ASSERT_ARG(len_out);
+       GIT_ASSERT_ARG(type_out);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(oid);
 
        backend = (loose_backend *)_backend;
        *stream_out = NULL;
@@ -1108,11 +1121,7 @@ static int loose_backend__freshen(
 
 static void loose_backend__free(git_odb_backend *_backend)
 {
-       loose_backend *backend;
-       assert(_backend);
-       backend = (loose_backend *)_backend;
-
-       git__free(backend);
+       git__free(_backend);
 }
 
 int git_odb_backend_loose(
@@ -1126,7 +1135,8 @@ int git_odb_backend_loose(
        loose_backend *backend;
        size_t objects_dirlen, alloclen;
 
-       assert(backend_out && objects_dir);
+       GIT_ASSERT_ARG(backend_out);
+       GIT_ASSERT_ARG(objects_dir);
 
        objects_dirlen = strlen(objects_dir);
 
index 6d20b39baedf49e9be3e922123dc721c83ca7312..d08356a8d44ad2c16ad9998df9d3bd52edcde3ac 100644 (file)
@@ -156,7 +156,7 @@ int git_mempack_new(git_odb_backend **out)
 {
        struct memory_packer_db *db;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        db = git__calloc(1, sizeof(struct memory_packer_db));
        GIT_ERROR_CHECK_ALLOC(db);
index 86c858df1116f0a9ae8b2506059d1e4aeb25a929..f4cb9a558b7b5cc2f0c60a77b8f73469ee87d73c 100644 (file)
 #include "git2/repository.h"
 #include "git2/indexer.h"
 #include "git2/sys/odb_backend.h"
+#include "delta.h"
 #include "futils.h"
 #include "hash.h"
-#include "odb.h"
-#include "delta.h"
+#include "midx.h"
 #include "mwindow.h"
+#include "odb.h"
 #include "pack.h"
 
 #include "git2/odb_backend.h"
@@ -25,6 +26,8 @@
 
 struct pack_backend {
        git_odb_backend parent;
+       git_midx_file *midx;
+       git_vector midx_packs;
        git_vector packs;
        struct git_pack_file *last_found;
        char *pack_folder;
@@ -47,36 +50,43 @@ struct pack_writepack {
  *     Initialization of the Pack Backend
  *     --------------------------------------------------
  *
- *     # git_odb_backend_pack
- *     | Creates the pack backend structure, initializes the
- *     | callback pointers to our default read() and exist() methods,
- *     | and tries to preload all the known packfiles in the ODB.
+ * # git_odb_backend_pack
+ * | Creates the pack backend structure, initializes the
+ * | callback pointers to our default read() and exist() methods,
+ * | and tries to find the `pack` folder, if it exists. ODBs without a `pack`
+ * | folder are ignored altogether. If there is a `pack` folder, it tries to
+ * | preload all the known packfiles in the ODB.
  * |
- *     |-# packfile_load_all
- *      | Tries to find the `pack` folder, if it exists. ODBs without
- *      | a pack folder are ignored altogether. If there's a `pack` folder
- *      | we run a `dirent` callback through every file in the pack folder
- *      | to find our packfiles. The packfiles are then sorted according
- *      | to a sorting callback.
- *      |
- *      |-# packfile_load__cb
- *      | | This callback is called from `dirent` with every single file
- *      | | inside the pack folder. We find the packs by actually locating
- *      | | their index (ends in ".idx"). From that index, we verify that
- *      | | the corresponding packfile exists and is valid, and if so, we
- *     | | add it to the pack list.
- *      | |
- *      | |-# packfile_check
- *      |              Make sure that there's a packfile to back this index, and store
- *      |              some very basic information regarding the packfile itself,
- *      |              such as the full path, the size, and the modification time.
- *      |              We don't actually open the packfile to check for internal consistency.
- *     |
- *     |-# packfile_sort__cb
- *             Sort all the preloaded packs according to some specific criteria:
- *             we prioritize the "newer" packs because it's more likely they
- *             contain the objects we are looking for, and we prioritize local
- *             packs over remote ones.
+ * |-# pack_backend__refresh
+ *   | The `multi-pack-index` is loaded if it exists and is valid.
+ *   | Then we run a `dirent` callback through every file in the pack folder,
+ *   | even those present in `multi-pack-index`. The unindexed packfiles are
+ *   | then sorted according to a sorting callback.
+ *   |
+ *   |-# refresh_multi_pack_index
+ *   |   Detect the presence of the `multi-pack-index` file. If it needs to be
+ *   |   refreshed, frees the old copy and tries to load the new one, together
+ *   |   with all the packfiles it indexes. If the process fails, fall back to
+ *   |   the old behavior, as if the `multi-pack-index` file was not there.
+ *   |
+ *   |-# packfile_load__cb
+ *   | | This callback is called from `dirent` with every single file
+ *   | | inside the pack folder. We find the packs by actually locating
+ *   | | their index (ends in ".idx"). From that index, we verify that
+ *   | | the corresponding packfile exists and is valid, and if so, we
+ *   | | add it to the pack list.
+ *   | |
+ *   | # git_mwindow_get_pack
+ *   |   Make sure that there's a packfile to back this index, and store
+ *   |   some very basic information regarding the packfile itself,
+ *   |   such as the full path, the size, and the modification time.
+ *   |   We don't actually open the packfile to check for internal consistency.
+ *   |
+ *   |-# packfile_sort__cb
+ *       Sort all the preloaded packs according to some specific criteria:
+ *       we prioritize the "newer" packs because it's more likely they
+ *       contain the objects we are looking for, and we prioritize local
+ *       packs over remote ones.
  *
  *
  *
@@ -84,48 +94,66 @@ struct pack_writepack {
  *     A standard packed `exist` query for an OID
  *     --------------------------------------------------
  *
- * # pack_backend__exists
- * | Check if the given SHA1 oid exists in any of the packs
- * | that have been loaded for our ODB.
+ * # pack_backend__exists / pack_backend__exists_prefix
+ * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the
+ * | packs that have been loaded for our ODB.
  * |
- * |-# pack_entry_find
- *     | Iterate through all the packs that have been preloaded
- *     | (starting by the pack where the latest object was found)
- *     | to try to find the OID in one of them.
- *     |
- *     |-# pack_entry_find1
- *             | Check the index of an individual pack to see if the SHA1
- *             | OID can be found. If we can find the offset to that SHA1
- *             | inside of the index, that means the object is contained
- *             | inside of the packfile and we can stop searching.
- *             | Before returning, we verify that the packfile behing the
- *             | index we are searching still exists on disk.
- *             |
- *             |-# pack_entry_find_offset
- *             | | Mmap the actual index file to disk if it hasn't been opened
- *             | | yet, and run a binary search through it to find the OID.
- *             | | See <http://book.git-scm.com/7_the_packfile.html> for specifics
- *             | | on the Packfile Index format and how do we find entries in it.
- *             | |
- *             | |-# pack_index_open
- *             |       | Guess the name of the index based on the full path to the
- *             |       | packfile, open it and verify its contents. Only if the index
- *             |       | has not been opened already.
- *             |       |
- *             |       |-# pack_index_check
- *             |               Mmap the index file and do a quick run through the header
- *             |               to guess the index version (right now we support v1 and v2),
- *             |               and to verify that the size of the index makes sense.
- *             |
- *             |-# packfile_open
- *                     See `packfile_open` in Chapter 3
+ * |-# pack_entry_find / pack_entry_find_prefix
+ *   | If there is a multi-pack-index present, search the SHA1 oid in that
+ *   | index first. If it is not found there, iterate through all the unindexed
+ *   | packs that have been preloaded (starting by the pack where the latest
+ *   | object was found) to try to find the OID in one of them.
+ *   |
+ *   |-# git_midx_entry_find
+ *   |   Search for the SHA1 oid in the multi-pack-index. See
+ *   |   <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
+ *   |   for specifics on the multi-pack-index format and how do we find
+ *   |   entries in it.
+ *   |
+ *   |-# git_pack_entry_find
+ *     | Check the index of an individual unindexed pack to see if the SHA1
+ *     | OID can be found. If we can find the offset to that SHA1 inside of the
+ *     | index, that means the object is contained inside of the packfile and
+ *     | we can stop searching. Before returning, we verify that the
+ *     | packfile behing the index we are searching still exists on disk.
+ *     |
+ *     |-# pack_entry_find_offset
+ *       | Mmap the actual index file to disk if it hasn't been opened
+ *       | yet, and run a binary search through it to find the OID.
+ *       | See <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
+ *       | for specifics on the Packfile Index format and how do we find
+ *       | entries in it.
+ *       |
+ *       |-# pack_index_open
+ *         | Guess the name of the index based on the full path to the
+ *         | packfile, open it and verify its contents. Only if the index
+ *         | has not been opened already.
+ *         |
+ *         |-# pack_index_check
+ *             Mmap the index file and do a quick run through the header
+ *             to guess the index version (right now we support v1 and v2),
+ *             and to verify that the size of the index makes sense.
  *
  *
  *
  *     Chapter 3: The neverending story...
  *     A standard packed `lookup` query for an OID
  *     --------------------------------------------------
- *     TODO
+ *
+ * # pack_backend__read / pack_backend__read_prefix
+ * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the
+ * | packs that have been loaded for our ODB. If it does, open the packfile and
+ * | read from it.
+ * |
+ * |-# git_packfile_unpack
+ *     Armed with a packfile and the offset within it, we can finally unpack
+ *     the object pointed at by the SHA1 oid. This involves mmapping part of
+ *     the `.pack` file, and uncompressing the object within it (if it is
+ *     stored in the undelfitied representation), or finding a base object and
+ *     applying some deltas to its uncompressed representation (if it is stored
+ *     in the deltified representation). See
+ *     <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
+ *     for specifics on the Packfile format and how do we read from it.
  *
  */
 
@@ -140,6 +168,8 @@ static int packfile_sort__cb(const void *a_, const void *b_);
 
 static int packfile_load__cb(void *_data, git_buf *path);
 
+static int packfile_byname_search_cmp(const void *path, const void *pack_entry);
+
 static int pack_entry_find(struct git_pack_entry *e,
        struct pack_backend *backend, const git_oid *oid);
 
@@ -163,6 +193,14 @@ static int pack_entry_find_prefix(
  *
  ***********************************************************/
 
+static int packfile_byname_search_cmp(const void *path_, const void *p_)
+{
+       const git_buf *path = (const git_buf *)path_;
+       const struct git_pack_file *p = (const struct git_pack_file *)p_;
+
+       return strncmp(p->pack_name, git_buf_cstr(path), git_buf_len(path));
+}
+
 static int packfile_sort__cb(const void *a_, const void *b_)
 {
        const struct git_pack_file *a = a_;
@@ -198,20 +236,20 @@ static int packfile_load__cb(void *data, git_buf *path)
        struct pack_backend *backend = data;
        struct git_pack_file *pack;
        const char *path_str = git_buf_cstr(path);
-       size_t i, cmp_len = git_buf_len(path);
+       git_buf index_prefix = GIT_BUF_INIT;
+       size_t cmp_len = git_buf_len(path);
        int error;
 
        if (cmp_len <= strlen(".idx") || git__suffixcmp(path_str, ".idx") != 0)
                return 0; /* not an index */
 
        cmp_len -= strlen(".idx");
+       git_buf_attach_notowned(&index_prefix, path_str, cmp_len);
 
-       for (i = 0; i < backend->packs.length; ++i) {
-               struct git_pack_file *p = git_vector_get(&backend->packs, i);
-
-               if (strncmp(p->pack_name, path_str, cmp_len) == 0)
-                       return 0;
-       }
+       if (git_vector_search2(NULL, &backend->midx_packs, packfile_byname_search_cmp, &index_prefix) == 0)
+               return 0;
+       if (git_vector_search2(NULL, &backend->packs, packfile_byname_search_cmp, &index_prefix) == 0)
+               return 0;
 
        error = git_mwindow_get_pack(&pack, path->ptr);
 
@@ -228,22 +266,26 @@ static int packfile_load__cb(void *data, git_buf *path)
 
 }
 
-static int pack_entry_find_inner(
-       struct git_pack_entry *e,
-       struct pack_backend *backend,
-       const git_oid *oid,
-       struct git_pack_file *last_found)
+static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
 {
+       struct git_pack_file *last_found = backend->last_found, *p;
+       git_midx_entry midx_entry;
        size_t i;
 
+       if (backend->midx &&
+               git_midx_entry_find(&midx_entry, backend->midx, oid, GIT_OID_HEXSZ) == 0 &&
+               midx_entry.pack_index < git_vector_length(&backend->midx_packs)) {
+               e->offset = midx_entry.offset;
+               git_oid_cpy(&e->sha1, &midx_entry.sha1);
+               e->p = git_vector_get(&backend->midx_packs, midx_entry.pack_index);
+               return 0;
+       }
+
        if (last_found &&
                git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0)
                return 0;
 
-       for (i = 0; i < backend->packs.length; ++i) {
-               struct git_pack_file *p;
-
-               p = git_vector_get(&backend->packs, i);
+       git_vector_foreach(&backend->packs, i, p) {
                if (p == last_found)
                        continue;
 
@@ -253,20 +295,6 @@ static int pack_entry_find_inner(
                }
        }
 
-       return -1;
-}
-
-static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
-{
-       struct git_pack_file *last_found = backend->last_found;
-
-       if (backend->last_found &&
-               git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
-               return 0;
-
-       if (!pack_entry_find_inner(e, backend, oid, last_found))
-               return 0;
-
        return git_odb__error_notfound(
                "failed to find pack entry", oid, GIT_OID_HEXSZ);
 }
@@ -281,22 +309,35 @@ static int pack_entry_find_prefix(
        size_t i;
        git_oid found_full_oid = {{0}};
        bool found = false;
-       struct git_pack_file *last_found = backend->last_found;
+       struct git_pack_file *last_found = backend->last_found, *p;
+       git_midx_entry midx_entry;
+
+       if (backend->midx) {
+               error = git_midx_entry_find(&midx_entry, backend->midx, short_oid, len);
+               if (error == GIT_EAMBIGUOUS)
+                       return error;
+               if (!error && midx_entry.pack_index < git_vector_length(&backend->midx_packs)) {
+                       e->offset = midx_entry.offset;
+                       git_oid_cpy(&e->sha1, &midx_entry.sha1);
+                       e->p = git_vector_get(&backend->midx_packs, midx_entry.pack_index);
+                       git_oid_cpy(&found_full_oid, &e->sha1);
+                       found = true;
+               }
+       }
 
        if (last_found) {
                error = git_pack_entry_find(e, last_found, short_oid, len);
                if (error == GIT_EAMBIGUOUS)
                        return error;
                if (!error) {
+                       if (found && git_oid_cmp(&e->sha1, &found_full_oid))
+                               return git_odb__error_ambiguous("found multiple pack entries");
                        git_oid_cpy(&found_full_oid, &e->sha1);
                        found = true;
                }
        }
 
-       for (i = 0; i < backend->packs.length; ++i) {
-               struct git_pack_file *p;
-
-               p = git_vector_get(&backend->packs, i);
+       git_vector_foreach(&backend->packs, i, p) {
                if (p == last_found)
                        continue;
 
@@ -319,6 +360,139 @@ static int pack_entry_find_prefix(
                return 0;
 }
 
+/***********************************************************
+ *
+ * MULTI-PACK-INDEX SUPPORT
+ *
+ * Functions needed to support the multi-pack-index.
+ *
+ ***********************************************************/
+
+/*
+ * Remove the multi-pack-index, and move all midx_packs to packs.
+ */
+static int remove_multi_pack_index(struct pack_backend *backend)
+{
+       size_t i, j = git_vector_length(&backend->packs);
+       struct pack_backend *p;
+       int error = git_vector_size_hint(
+                       &backend->packs,
+                       j + git_vector_length(&backend->midx_packs));
+       if (error < 0)
+               return error;
+
+       git_vector_foreach(&backend->midx_packs, i, p)
+               git_vector_set(NULL, &backend->packs, j++, p);
+       git_vector_clear(&backend->midx_packs);
+
+       git_midx_free(backend->midx);
+       backend->midx = NULL;
+
+       return 0;
+}
+
+/*
+ * Loads a single .pack file referred to by the multi-pack-index. These must
+ * match the order in which they are declared in the multi-pack-index file,
+ * since these files are referred to by their index.
+ */
+static int process_multi_pack_index_pack(
+               struct pack_backend *backend,
+               size_t i,
+               const char *packfile_name)
+{
+       int error;
+       struct git_pack_file *pack;
+       size_t found_position;
+       git_buf pack_path = GIT_BUF_INIT, index_prefix = GIT_BUF_INIT;
+
+       error = git_buf_joinpath(&pack_path, backend->pack_folder, packfile_name);
+       if (error < 0)
+               return error;
+
+       /* This is ensured by midx_parse_packfile_name() */
+       if (git_buf_len(&pack_path) <= strlen(".idx") || git__suffixcmp(git_buf_cstr(&pack_path), ".idx") != 0)
+               return git_odb__error_notfound("midx file contained a non-index", NULL, 0);
+
+       git_buf_attach_notowned(&index_prefix, git_buf_cstr(&pack_path), git_buf_len(&pack_path) - strlen(".idx"));
+
+       if (git_vector_search2(&found_position, &backend->packs, packfile_byname_search_cmp, &index_prefix) == 0) {
+               /* Pack was found in the packs list. Moving it to the midx_packs list. */
+               git_buf_dispose(&pack_path);
+               git_vector_set(NULL, &backend->midx_packs, i, git_vector_get(&backend->packs, found_position));
+               git_vector_remove(&backend->packs, found_position);
+               return 0;
+       }
+
+       /* Pack was not found. Allocate a new one. */
+       error = git_mwindow_get_pack(&pack, git_buf_cstr(&pack_path));
+       git_buf_dispose(&pack_path);
+       if (error < 0)
+               return error;
+
+       git_vector_set(NULL, &backend->midx_packs, i, pack);
+       return 0;
+}
+
+/*
+ * Reads the multi-pack-index. If this fails for whatever reason, the
+ * multi-pack-index object is freed, and all the packfiles that are related to
+ * it are moved to the unindexed packfiles vector.
+ */
+static int refresh_multi_pack_index(struct pack_backend *backend)
+{
+       int error;
+       git_buf midx_path = GIT_BUF_INIT;
+       const char *packfile_name;
+       size_t i;
+
+       error = git_buf_joinpath(&midx_path, backend->pack_folder, "multi-pack-index");
+       if (error < 0)
+               return error;
+
+       /*
+        * Check whether the multi-pack-index has changed. If it has, close any
+        * old multi-pack-index and move all the packfiles to the unindexed
+        * packs. This is done to prevent losing any open packfiles in case
+        * refreshing the new multi-pack-index fails, or the file is deleted.
+        */
+       if (backend->midx) {
+               if (!git_midx_needs_refresh(backend->midx, git_buf_cstr(&midx_path))) {
+                       git_buf_dispose(&midx_path);
+                       return 0;
+               }
+               error = remove_multi_pack_index(backend);
+               if (error < 0) {
+                       git_buf_dispose(&midx_path);
+                       return error;
+               }
+       }
+
+       error = git_midx_open(&backend->midx, git_buf_cstr(&midx_path));
+       git_buf_dispose(&midx_path);
+       if (error < 0)
+               return error;
+
+       git_vector_resize_to(&backend->midx_packs, git_vector_length(&backend->midx->packfile_names));
+
+       git_vector_foreach(&backend->midx->packfile_names, i, packfile_name) {
+               error = process_multi_pack_index_pack(backend, i, packfile_name);
+               if (error < 0) {
+                       /*
+                        * Something failed during reading multi-pack-index.
+                        * Restore the state of backend as if the
+                        * multi-pack-index was never there, and move all
+                        * packfiles that have been processed so far to the
+                        * unindexed packs.
+                        */
+                       git_vector_resize_to(&backend->midx_packs, i);
+                       remove_multi_pack_index(backend);
+                       return error;
+               }
+       }
+
+       return 0;
+}
 
 /***********************************************************
  *
@@ -340,9 +514,16 @@ static int pack_backend__refresh(git_odb_backend *backend_)
        if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
                return git_odb__error_notfound("failed to refresh packfiles", NULL, 0);
 
-       git_buf_sets(&path, backend->pack_folder);
+       if (refresh_multi_pack_index(backend) < 0) {
+               /*
+                * It is okay if this fails. We will just not use the
+                * multi-pack-index in this case.
+                */
+               git_error_clear();
+       }
 
        /* reload all packs */
+       git_buf_sets(&path, backend->pack_folder);
        error = git_path_direach(&path, 0, packfile_load__cb, backend);
 
        git_buf_dispose(&path);
@@ -358,7 +539,10 @@ static int pack_backend__read_header(
        struct git_pack_entry e;
        int error;
 
-       assert(len_p && type_p && backend && oid);
+       GIT_ASSERT_ARG(len_p);
+       GIT_ASSERT_ARG(type_p);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(oid);
 
        if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
                return error;
@@ -469,13 +653,17 @@ static int pack_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb c
        struct pack_backend *backend;
        unsigned int i;
 
-       assert(_backend && cb);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(cb);
+
        backend = (struct pack_backend *)_backend;
 
        /* Make sure we know about the packfiles */
-       if ((error = pack_backend__refresh(_backend)) < 0)
+       if ((error = pack_backend__refresh(_backend)) != 0)
                return error;
 
+       if (backend->midx && (error = git_midx_foreach_entry(backend->midx, cb, data)) != 0)
+               return error;
        git_vector_foreach(&backend->packs, i, p) {
                if ((error = git_pack_foreach_entry(p, cb, data)) != 0)
                        return error;
@@ -488,7 +676,7 @@ static int pack_backend__writepack_append(struct git_odb_writepack *_writepack,
 {
        struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
 
-       assert(writepack);
+       GIT_ASSERT_ARG(writepack);
 
        return git_indexer_append(writepack->indexer, data, size, stats);
 }
@@ -497,16 +685,19 @@ static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack,
 {
        struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
 
-       assert(writepack);
+       GIT_ASSERT_ARG(writepack);
 
        return git_indexer_commit(writepack->indexer, stats);
 }
 
 static void pack_backend__writepack_free(struct git_odb_writepack *_writepack)
 {
-       struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
+       struct pack_writepack *writepack;
 
-       assert(writepack);
+       if (!_writepack)
+               return;
+
+       writepack = (struct pack_writepack *)_writepack;
 
        git_indexer_free(writepack->indexer);
        git__free(writepack);
@@ -522,7 +713,8 @@ static int pack_backend__writepack(struct git_odb_writepack **out,
        struct pack_backend *backend;
        struct pack_writepack *writepack;
 
-       assert(out && _backend);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(_backend);
 
        *out = NULL;
 
@@ -550,20 +742,99 @@ static int pack_backend__writepack(struct git_odb_writepack **out,
        return 0;
 }
 
+static int get_idx_path(
+               git_buf *idx_path,
+               struct pack_backend *backend,
+               struct git_pack_file *p)
+{
+       size_t path_len;
+       int error;
+
+       error = git_path_prettify(idx_path, p->pack_name, backend->pack_folder);
+       if (error < 0)
+               return error;
+       path_len = git_buf_len(idx_path);
+       if (path_len <= strlen(".pack") || git__suffixcmp(git_buf_cstr(idx_path), ".pack") != 0)
+               return git_odb__error_notfound("packfile does not end in .pack", NULL, 0);
+       path_len -= strlen(".pack");
+       error = git_buf_splice(idx_path, path_len, strlen(".pack"), ".idx", strlen(".idx"));
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+static int pack_backend__writemidx(git_odb_backend *_backend)
+{
+       struct pack_backend *backend;
+       git_midx_writer *w = NULL;
+       struct git_pack_file *p;
+       size_t i;
+       int error = 0;
+
+       GIT_ASSERT_ARG(_backend);
+
+       backend = (struct pack_backend *)_backend;
+
+       error = git_midx_writer_new(&w, backend->pack_folder);
+       if (error < 0)
+               return error;
+
+       git_vector_foreach(&backend->midx_packs, i, p) {
+               git_buf idx_path = GIT_BUF_INIT;
+               error = get_idx_path(&idx_path, backend, p);
+               if (error < 0)
+                       goto cleanup;
+               error = git_midx_writer_add(w, git_buf_cstr(&idx_path));
+               git_buf_dispose(&idx_path);
+               if (error < 0)
+                       goto cleanup;
+       }
+       git_vector_foreach(&backend->packs, i, p) {
+               git_buf idx_path = GIT_BUF_INIT;
+               error = get_idx_path(&idx_path, backend, p);
+               if (error < 0)
+                       goto cleanup;
+               error = git_midx_writer_add(w, git_buf_cstr(&idx_path));
+               git_buf_dispose(&idx_path);
+               if (error < 0)
+                       goto cleanup;
+       }
+
+       /*
+        * Invalidate the previous midx before writing the new one.
+        */
+       error = remove_multi_pack_index(backend);
+       if (error < 0)
+               goto cleanup;
+       error = git_midx_writer_commit(w);
+       if (error < 0)
+               goto cleanup;
+       error = refresh_multi_pack_index(backend);
+
+cleanup:
+       git_midx_writer_free(w);
+       return error;
+}
+
 static void pack_backend__free(git_odb_backend *_backend)
 {
        struct pack_backend *backend;
+       struct git_pack_file *p;
        size_t i;
 
-       assert(_backend);
+       if (!_backend)
+               return;
 
        backend = (struct pack_backend *)_backend;
 
-       for (i = 0; i < backend->packs.length; ++i) {
-               struct git_pack_file *p = git_vector_get(&backend->packs, i);
+       git_vector_foreach(&backend->midx_packs, i, p)
+               git_mwindow_put_pack(p);
+       git_vector_foreach(&backend->packs, i, p)
                git_mwindow_put_pack(p);
-       }
 
+       git_midx_free(backend->midx);
+       git_vector_free(&backend->midx_packs);
        git_vector_free(&backend->packs);
        git__free(backend->pack_folder);
        git__free(backend);
@@ -574,7 +845,12 @@ static int pack_backend__alloc(struct pack_backend **out, size_t initial_size)
        struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend));
        GIT_ERROR_CHECK_ALLOC(backend);
 
+       if (git_vector_init(&backend->midx_packs, 0, NULL) < 0) {
+               git__free(backend);
+               return -1;
+       }
        if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) {
+               git_vector_free(&backend->midx_packs);
                git__free(backend);
                return -1;
        }
@@ -589,6 +865,7 @@ static int pack_backend__alloc(struct pack_backend **out, size_t initial_size)
        backend->parent.refresh = &pack_backend__refresh;
        backend->parent.foreach = &pack_backend__foreach;
        backend->parent.writepack = &pack_backend__writepack;
+       backend->parent.writemidx = &pack_backend__writemidx;
        backend->parent.freshen = &pack_backend__freshen;
        backend->parent.free = &pack_backend__free;
 
index 7831aca89bee12020cb55febc04fbee2aa389017..893e2fc0fb0620ea03a5e8cb7cbaa8be71ae89c6 100644 (file)
--- a/src/oid.c
+++ b/src/oid.c
@@ -9,7 +9,7 @@
 
 #include "git2/oid.h"
 #include "repository.h"
-#include "global.h"
+#include "threadstate.h"
 #include <string.h>
 #include <limits.h>
 
@@ -26,7 +26,8 @@ int git_oid_fromstrn(git_oid *out, const char *str, size_t length)
        size_t p;
        int v;
 
-       assert(out && str);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(str);
 
        if (!length)
                return oid_error_invalid("too short");
@@ -107,7 +108,7 @@ int git_oid_pathfmt(char *str, const git_oid *oid)
 
 char *git_oid_tostr_s(const git_oid *oid)
 {
-       char *str = GIT_GLOBAL->oid_fmt;
+       char *str = GIT_THREADSTATE->oid_fmt;
        git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid);
        return str;
 }
@@ -316,7 +317,7 @@ git_oid_shorten *git_oid_shorten_new(size_t min_length)
 {
        git_oid_shorten *os;
 
-       assert((size_t)((int)min_length) == min_length);
+       GIT_ASSERT_ARG_WITH_RETVAL((size_t)((int)min_length) == min_length, NULL);
 
        os = git__calloc(1, sizeof(git_oid_shorten));
        if (os == NULL)
index e70e9dd6185890fa98bcad0be0253ab4bd7c31fc..583017c4ee2b9379285585382d6e12814a5aa4eb 100644 (file)
@@ -10,7 +10,7 @@
 #include "git2/oidarray.h"
 #include "array.h"
 
-void git_oidarray_free(git_oidarray *arr)
+void git_oidarray_dispose(git_oidarray *arr)
 {
        git__free(arr->ids);
 }
@@ -32,3 +32,12 @@ void git_oidarray__reverse(git_oidarray *arr)
                git_oid_cpy(&arr->ids[(arr->count-1)-i], &tmp);
        }
 }
+
+#ifndef GIT_DEPRECATE_HARD
+
+void git_oidarray_free(git_oidarray *arr)
+{
+       git_oidarray_dispose(arr);
+}
+
+#endif
index cf10e6cb5a6284f4c6831326bfbc779cb99b12a5..faff310b40b57deb36618e08151f155f945293a4 100644 (file)
@@ -12,7 +12,7 @@
 #include "iterator.h"
 #include "netops.h"
 #include "pack.h"
-#include "thread-utils.h"
+#include "thread.h"
 #include "tree.h"
 #include "util.h"
 #include "revwalk.h"
@@ -48,18 +48,10 @@ struct walk_object {
 };
 
 #ifdef GIT_THREADS
-
-#define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \
-               int result = git_mutex_##op(&(pb)->mtx); \
-               assert(!result); \
-               GIT_UNUSED(result); \
-       } while (0)
-
+# define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) git_mutex_##op(&(pb)->mtx)
 #else
-
-#define GIT_PACKBUILDER__MUTEX_OP(pb,mtx,op) GIT_UNUSED(pb)
-
-#endif /* GIT_THREADS */
+# define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) git__noop()
+#endif
 
 #define git_packbuilder__cache_lock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, cache_mutex, lock)
 #define git_packbuilder__cache_unlock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, cache_mutex, unlock)
@@ -177,13 +169,13 @@ on_error:
 
 unsigned int git_packbuilder_set_threads(git_packbuilder *pb, unsigned int n)
 {
-       assert(pb);
+       GIT_ASSERT_ARG(pb);
 
 #ifdef GIT_THREADS
        pb->nr_threads = n;
 #else
        GIT_UNUSED(n);
-       assert(1 == pb->nr_threads);
+       GIT_ASSERT(pb->nr_threads == 1);
 #endif
 
        return pb->nr_threads;
@@ -211,7 +203,8 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
        size_t newsize;
        int ret;
 
-       assert(pb && oid);
+       GIT_ASSERT_ARG(pb);
+       GIT_ASSERT_ARG(oid);
 
        /* If the object already exists in the hash table, then we don't
         * have any work to do */
@@ -258,7 +251,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
                double current_time = git__timer();
                double elapsed = current_time - pb->last_progress_report_time;
 
-               if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
+               if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
                        pb->last_progress_report_time = current_time;
 
                        ret = pb->progress_cb(
@@ -347,10 +340,9 @@ static int write_object(
        }
 
        /* Write header */
-       hdr_len = git_packfile__object_header(hdr, data_len, type);
-
-       if ((error = write_cb(hdr, hdr_len, cb_data)) < 0 ||
-               (error = git_hash_update(&pb->ctx, hdr, hdr_len)) < 0)
+       if ((error = git_packfile__object_header(&hdr_len, hdr, data_len, type)) < 0 ||
+           (error = write_cb(hdr, hdr_len, cb_data)) < 0 ||
+           (error = git_hash_update(&pb->ctx, hdr, hdr_len)) < 0)
                goto done;
 
        if (type == GIT_OBJECT_REF_DELTA) {
@@ -525,13 +517,18 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data)
        return 0;
 }
 
-static git_pobject **compute_write_order(git_packbuilder *pb)
+static int compute_write_order(git_pobject ***out, git_packbuilder *pb)
 {
        size_t i, wo_end, last_untagged;
        git_pobject **wo;
 
+       *out = NULL;
+
+       if (!pb->nr_objects)
+               return 0;
+
        if ((wo = git__mallocarray(pb->nr_objects, sizeof(*wo))) == NULL)
-               return NULL;
+               return -1;
 
        for (i = 0; i < pb->nr_objects; i++) {
                git_pobject *po = pb->object_list + i;
@@ -560,7 +557,7 @@ static git_pobject **compute_write_order(git_packbuilder *pb)
         */
        if (git_tag_foreach(pb->repo, &cb_tag_foreach, pb) < 0) {
                git__free(wo);
-               return NULL;
+               return -1;
        }
 
        /*
@@ -617,10 +614,11 @@ static git_pobject **compute_write_order(git_packbuilder *pb)
        if (wo_end != pb->nr_objects) {
                git__free(wo);
                git_error_set(GIT_ERROR_INVALID, "invalid write order");
-               return NULL;
+               return -1;
        }
 
-       return wo;
+       *out = wo;
+       return 0;
 }
 
 static int write_pack(git_packbuilder *pb,
@@ -633,15 +631,15 @@ static int write_pack(git_packbuilder *pb,
        struct git_pack_header ph;
        git_oid entry_oid;
        size_t i = 0;
-       int error = 0;
+       int error;
 
-       write_order = compute_write_order(pb);
-       if (write_order == NULL)
-               return -1;
+       if ((error = compute_write_order(&write_order, pb)) < 0)
+               return error;
 
        if (!git__is_uint32(pb->nr_objects)) {
                git_error_set(GIT_ERROR_INVALID, "too many objects");
-               return -1;
+               error = -1;
+               goto done;
        }
 
        /* Write pack header */
@@ -852,10 +850,11 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
                }
        }
 
-       git_packbuilder__cache_lock(pb);
+       GIT_ASSERT(git_packbuilder__cache_lock(pb) == 0);
+
        if (trg_object->delta_data) {
                git__free(trg_object->delta_data);
-               assert(pb->delta_cache_size >= trg_object->delta_size);
+               GIT_ASSERT(pb->delta_cache_size >= trg_object->delta_size);
                pb->delta_cache_size -= trg_object->delta_size;
                trg_object->delta_data = NULL;
        }
@@ -863,7 +862,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
                bool overflow = git__add_sizet_overflow(
                        &pb->delta_cache_size, pb->delta_cache_size, delta_size);
 
-               git_packbuilder__cache_unlock(pb);
+               GIT_ASSERT(git_packbuilder__cache_unlock(pb) == 0);
 
                if (overflow) {
                        git__free(delta_buf);
@@ -874,7 +873,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
                GIT_ERROR_CHECK_ALLOC(trg_object->delta_data);
        } else {
                /* create delta when writing the pack */
-               git_packbuilder__cache_unlock(pb);
+               GIT_ASSERT(git_packbuilder__cache_unlock(pb) == 0);
                git__free(delta_buf);
        }
 
@@ -929,7 +928,7 @@ static int report_delta_progress(
                double current_time = git__timer();
                double elapsed = current_time - pb->last_progress_report_time;
 
-               if (force || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
+               if (force || elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
                        pb->last_progress_report_time = current_time;
 
                        ret = pb->progress_cb(
@@ -962,9 +961,9 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
                struct unpacked *n = array + idx;
                size_t max_depth, j, best_base = SIZE_MAX;
 
-               git_packbuilder__progress_lock(pb);
+               GIT_ASSERT(git_packbuilder__progress_lock(pb) == 0);
                if (!*list_size) {
-                       git_packbuilder__progress_unlock(pb);
+                       GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
                        break;
                }
 
@@ -973,7 +972,7 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
 
                po = *list++;
                (*list_size)--;
-               git_packbuilder__progress_unlock(pb);
+               GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
 
                mem_usage -= free_unpacked(n);
                n->object = po;
@@ -1048,10 +1047,10 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
                        po->z_delta_size = zbuf.size;
                        git_buf_clear(&zbuf);
 
-                       git_packbuilder__cache_lock(pb);
+                       GIT_ASSERT(git_packbuilder__cache_lock(pb) == 0);
                        pb->delta_cache_size -= po->delta_size;
                        pb->delta_cache_size += po->z_delta_size;
-                       git_packbuilder__cache_unlock(pb);
+                       GIT_ASSERT(git_packbuilder__cache_unlock(pb) == 0);
                }
 
                /*
@@ -1129,10 +1128,10 @@ static void *threaded_find_deltas(void *arg)
                        ; /* TODO */
                }
 
-               git_packbuilder__progress_lock(me->pb);
+               GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL);
                me->working = 0;
                git_cond_signal(&me->pb->progress_cond);
-               git_packbuilder__progress_unlock(me->pb);
+               GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_unlock(me->pb) == 0, NULL);
 
                if (git_mutex_lock(&me->mutex)) {
                        git_error_set(GIT_ERROR_THREAD, "unable to lock packfile condition mutex");
@@ -1165,7 +1164,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
        int ret, active_threads = 0;
 
        if (!pb->nr_threads)
-               pb->nr_threads = git_online_cpus();
+               pb->nr_threads = git__online_cpus();
 
        if (pb->nr_threads <= 1) {
                find_deltas(pb, list, &list_size, window, depth);
@@ -1237,7 +1236,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
                 * 'working' flag from 1 -> 0. This indicates that it is
                 * ready to receive more work using our work-stealing
                 * algorithm. */
-               git_packbuilder__progress_lock(pb);
+               GIT_ASSERT(git_packbuilder__progress_lock(pb) == 0);
                for (;;) {
                        for (i = 0; !target && i < pb->nr_threads; i++)
                                if (!p[i].working)
@@ -1280,7 +1279,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
                target->list_size = sub_size;
                target->remaining = sub_size;
                target->working = 1;
-               git_packbuilder__progress_unlock(pb);
+               GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
 
                if (git_mutex_lock(&target->mutex)) {
                        git_error_set(GIT_ERROR_THREAD, "unable to lock packfile condition mutex");
@@ -1363,8 +1362,13 @@ int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t siz
 
 int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb)
 {
+       int error;
+
+       if ((error = git_buf_sanitize(buf)) < 0)
+               return error;
+
        PREPARE_PACK;
-       git_buf_sanitize(buf);
+
        return write_pack(pb, &write_pack_buf, buf);
 }
 
@@ -1486,7 +1490,8 @@ int git_packbuilder_insert_recur(git_packbuilder *pb, const git_oid *id, const c
        git_object *obj;
        int error;
 
-       assert(pb && id);
+       GIT_ASSERT_ARG(pb);
+       GIT_ASSERT_ARG(id);
 
        if ((error = git_object_lookup(&obj, pb->repo, id, GIT_OBJECT_ANY)) < 0)
                return error;
@@ -1727,7 +1732,8 @@ int git_packbuilder_insert_walk(git_packbuilder *pb, git_revwalk *walk)
        git_oid id;
        struct walk_object *obj;
 
-       assert(pb && walk);
+       GIT_ASSERT_ARG(pb);
+       GIT_ASSERT_ARG(walk);
 
        if ((error = mark_edges_uninteresting(pb, walk->user_input)) < 0)
                return error;
index 1b5cf670f8d65cc824816ede77c96fbceb95f831..aadf3f2be7c74eb84ea488de08fd6c1b9fbd3c16 100644 (file)
 #include "mwindow.h"
 #include "odb.h"
 #include "oid.h"
+#include "oidarray.h"
 
 /* Option to bypass checking existence of '.keep' files */
 bool git_disable_pack_keep_file_checks = false;
 
-static int packfile_open(struct git_pack_file *p);
-static off64_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
+static int packfile_open_locked(struct git_pack_file *p);
+static off64_t nth_packed_object_offset_locked(struct git_pack_file *p, uint32_t n);
 static int packfile_unpack_compressed(
                git_rawobj *obj,
                struct git_pack_file *p,
@@ -56,7 +57,7 @@ static git_pack_cache_entry *new_cache_object(git_rawobj *source)
        if (!e)
                return NULL;
 
-       git_atomic_inc(&e->refcount);
+       git_atomic32_inc(&e->refcount);
        memcpy(&e->raw, source, sizeof(git_rawobj));
 
        return e;
@@ -67,7 +68,6 @@ static void free_cache_object(void *o)
        git_pack_cache_entry *e = (git_pack_cache_entry *)o;
 
        if (e != NULL) {
-               assert(e->refcount.val == 0);
                git__free(e->raw.data);
                git__free(e);
        }
@@ -114,7 +114,7 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, off64_t offset)
                return NULL;
 
        if ((entry = git_offmap_get(cache->entries, offset)) != NULL) {
-               git_atomic_inc(&entry->refcount);
+               git_atomic32_inc(&entry->refcount);
                entry->last_usage = cache->use_ctr++;
        }
        git_mutex_unlock(&cache->lock);
@@ -129,7 +129,7 @@ static void free_lowest_entry(git_pack_cache *cache)
        git_pack_cache_entry *entry;
 
        git_offmap_foreach(cache->entries, offset, entry, {
-               if (entry && entry->refcount.val == 0) {
+               if (entry && git_atomic32_get(&entry->refcount) == 0) {
                        cache->memory_used -= entry->raw.len;
                        git_offmap_delete(cache->entries, offset);
                        free_cache_object(entry);
@@ -196,7 +196,8 @@ static void pack_index_free(struct git_pack_file *p)
        }
 }
 
-static int pack_index_check(const char *path, struct git_pack_file *p)
+/* Run with the packfile lock held */
+static int pack_index_check_locked(const char *path, struct git_pack_file *p)
 {
        struct git_pack_idx_header *hdr;
        uint32_t version, nr, i, *index;
@@ -302,40 +303,36 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
        return 0;
 }
 
-static int pack_index_open(struct git_pack_file *p)
+/* Run with the packfile lock held */
+static int pack_index_open_locked(struct git_pack_file *p)
 {
        int error = 0;
        size_t name_len;
-       git_buf idx_name;
+       git_buf idx_name = GIT_BUF_INIT;
 
        if (p->index_version > -1)
-               return 0;
+               goto cleanup;
 
+       /* checked by git_pack_file alloc */
        name_len = strlen(p->pack_name);
-       assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */
+       GIT_ASSERT(name_len > strlen(".pack"));
 
-       if (git_buf_init(&idx_name, name_len) < 0)
-               return -1;
+       if ((error = git_buf_init(&idx_name, name_len)) < 0)
+               goto cleanup;
 
        git_buf_put(&idx_name, p->pack_name, name_len - strlen(".pack"));
        git_buf_puts(&idx_name, ".idx");
        if (git_buf_oom(&idx_name)) {
-               git_buf_dispose(&idx_name);
-               return -1;
-       }
-
-       if ((error = git_mutex_lock(&p->lock)) < 0) {
-               git_buf_dispose(&idx_name);
-               return error;
+               error = -1;
+               goto cleanup;
        }
 
        if (p->index_version == -1)
-               error = pack_index_check(idx_name.ptr, p);
+               error = pack_index_check_locked(idx_name.ptr, p);
 
+cleanup:
        git_buf_dispose(&idx_name);
 
-       git_mutex_unlock(&p->lock);
-
        return error;
 }
 
@@ -345,8 +342,20 @@ static unsigned char *pack_window_open(
                off64_t offset,
                unsigned int *left)
 {
-       if (p->mwf.fd == -1 && packfile_open(p) < 0)
+       unsigned char *pack_data = NULL;
+
+       if (git_mutex_lock(&p->lock) < 0) {
+               git_error_set(GIT_ERROR_THREAD, "unable to lock packfile");
+               return NULL;
+       }
+       if (git_mutex_lock(&p->mwf.lock) < 0) {
+               git_mutex_unlock(&p->lock);
+               git_error_set(GIT_ERROR_THREAD, "unable to lock packfile");
                return NULL;
+       }
+
+       if (p->mwf.fd == -1 && packfile_open_locked(p) < 0)
+               goto cleanup;
 
        /* Since packfiles end in a hash of their content and it's
         * pointless to ask for an offset into the middle of that
@@ -357,11 +366,16 @@ static unsigned char *pack_window_open(
         * around.
         */
        if (offset > (p->mwf.size - 20))
-               return NULL;
+               goto cleanup;
        if (offset < 0)
-               return NULL;
+               goto cleanup;
+
+       pack_data = git_mwindow_open(&p->mwf, w_cursor, offset, 20, left);
 
-       return git_mwindow_open(&p->mwf, w_cursor, offset, 20, left);
+cleanup:
+       git_mutex_unlock(&p->mwf.lock);
+       git_mutex_unlock(&p->lock);
+       return pack_data;
  }
 
 /*
@@ -372,12 +386,12 @@ static unsigned char *pack_window_open(
  *  - each byte afterwards: low seven bits are size continuation,
  *    with the high bit being "size continues"
  */
-size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_object_t type)
+int git_packfile__object_header(size_t *out, unsigned char *hdr, size_t size, git_object_t type)
 {
        unsigned char *hdr_base;
        unsigned char c;
 
-       assert(type >= GIT_OBJECT_COMMIT && type <= GIT_OBJECT_REF_DELTA);
+       GIT_ASSERT_ARG(type >= GIT_OBJECT_COMMIT && type <= GIT_OBJECT_REF_DELTA);
 
        /* TODO: add support for chunked objects; see git.git 6c0d19b1 */
 
@@ -392,7 +406,8 @@ size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_object_t
        }
        *hdr++ = c;
 
-       return (hdr - hdr_base);
+       *out = (hdr - hdr_base);
+       return 0;
 }
 
 
@@ -436,14 +451,27 @@ static int packfile_unpack_header1(
 int git_packfile_unpack_header(
                size_t *size_p,
                git_object_t *type_p,
-               git_mwindow_file *mwf,
+               struct git_pack_file *p,
                git_mwindow **w_curs,
                off64_t *curpos)
 {
        unsigned char *base;
        unsigned int left;
        unsigned long used;
-       int ret;
+       int error;
+
+       if ((error = git_mutex_lock(&p->lock)) < 0)
+               return error;
+       if ((error = git_mutex_lock(&p->mwf.lock)) < 0) {
+               git_mutex_unlock(&p->lock);
+               return error;
+       }
+
+       if (p->mwf.fd == -1 && (error = packfile_open_locked(p)) < 0) {
+               git_mutex_unlock(&p->lock);
+               git_mutex_unlock(&p->mwf.lock);
+               return error;
+       }
 
        /* pack_window_open() assures us we have [base, base + 20) available
         * as a range that we can look at at. (Its actually the hash
@@ -451,16 +479,17 @@ int git_packfile_unpack_header(
         * the maximum deflated object size is 2^137, which is just
         * insane, so we know won't exceed what we have been given.
         */
-/*     base = pack_window_open(p, w_curs, *curpos, &left); */
-       base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
+       base = git_mwindow_open(&p->mwf, w_curs, *curpos, 20, &left);
+       git_mutex_unlock(&p->lock);
+       git_mutex_unlock(&p->mwf.lock);
        if (base == NULL)
                return GIT_EBUFS;
 
-       ret = packfile_unpack_header1(&used, size_p, type_p, base, left);
+       error = packfile_unpack_header1(&used, size_p, type_p, base, left);
        git_mwindow_close(w_curs);
-       if (ret == GIT_EBUFS)
-               return ret;
-       else if (ret < 0)
+       if (error == GIT_EBUFS)
+               return error;
+       else if (error < 0)
                return packfile_error("header length is zero");
 
        *curpos += used;
@@ -480,7 +509,27 @@ int git_packfile_resolve_header(
        off64_t base_offset;
        int error;
 
-       error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
+       error = git_mutex_lock(&p->lock);
+       if (error < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               return error;
+       }
+       error = git_mutex_lock(&p->mwf.lock);
+       if (error < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               git_mutex_unlock(&p->lock);
+               return error;
+       }
+
+       if (p->mwf.fd == -1 && (error = packfile_open_locked(p)) < 0) {
+               git_mutex_unlock(&p->mwf.lock);
+               git_mutex_unlock(&p->lock);
+               return error;
+       }
+       git_mutex_unlock(&p->mwf.lock);
+       git_mutex_unlock(&p->lock);
+
+       error = git_packfile_unpack_header(&size, &type, p, &w_curs, &curpos);
        if (error < 0)
                return error;
 
@@ -507,7 +556,7 @@ int git_packfile_resolve_header(
 
        while (type == GIT_OBJECT_OFS_DELTA || type == GIT_OBJECT_REF_DELTA) {
                curpos = base_offset;
-               error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
+               error = git_packfile_unpack_header(&size, &type, p, &w_curs, &curpos);
                if (error < 0)
                        return error;
                if (type != GIT_OBJECT_OFS_DELTA && type != GIT_OBJECT_REF_DELTA)
@@ -578,8 +627,7 @@ static int pack_dependency_chain(git_dependency_chain *chain_out,
 
                elem->base_key = obj_offset;
 
-               error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
-
+               error = git_packfile_unpack_header(&size, &type, p, &w_curs, &curpos);
                if (error < 0)
                        goto on_error;
 
@@ -630,6 +678,25 @@ int git_packfile_unpack(
        size_t stack_size = 0, elem_pos, alloclen;
        git_object_t base_type;
 
+       error = git_mutex_lock(&p->lock);
+       if (error < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               return error;
+       }
+       error = git_mutex_lock(&p->mwf.lock);
+       if (error < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               git_mutex_unlock(&p->lock);
+               return error;
+       }
+
+       if (p->mwf.fd == -1)
+               error = packfile_open_locked(p);
+       git_mutex_unlock(&p->mwf.lock);
+       git_mutex_unlock(&p->lock);
+       if (error < 0)
+               return error;
+
        /*
         * TODO: optionally check the CRC on the packfile
         */
@@ -692,7 +759,7 @@ int git_packfile_unpack(
                GIT_ERROR_CHECK_ALLOC(obj->data);
 
                memcpy(obj->data, data, obj->len + 1);
-               git_atomic_dec(&cached->refcount);
+               git_atomic32_dec(&cached->refcount);
                goto cleanup;
        }
 
@@ -740,7 +807,7 @@ int git_packfile_unpack(
                }
 
                if (cached) {
-                       git_atomic_dec(&cached->refcount);
+                       git_atomic32_dec(&cached->refcount);
                        cached = NULL;
                }
 
@@ -754,7 +821,7 @@ cleanup:
        if (error < 0) {
                git__free(obj->data);
                if (cached)
-                       git_atomic_dec(&cached->refcount);
+                       git_atomic32_dec(&cached->refcount);
        }
 
        if (elem)
@@ -841,7 +908,7 @@ static int packfile_unpack_compressed(
 
        do {
                size_t bytes = buffer_len - total;
-               unsigned int window_len;
+               unsigned int window_len, consumed;
                unsigned char *in;
 
                if ((in = pack_window_open(p, mwindow, *position, &window_len)) == NULL) {
@@ -857,10 +924,15 @@ static int packfile_unpack_compressed(
 
                git_mwindow_close(mwindow);
 
-               if (!bytes)
-                       break;
+               consumed = window_len - (unsigned int)zstream.in_len;
 
-               *position += window_len - zstream.in_len;
+               if (!bytes && !consumed) {
+                       git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream");
+                       error = -1;
+                       goto out;
+               }
+
+               *position += consumed;
                total += bytes;
        } while (!git_zstream_eos(&zstream));
 
@@ -899,7 +971,7 @@ int get_delta_base(
        off64_t base_offset;
        git_oid unused;
 
-       assert(delta_base_out);
+       GIT_ASSERT_ARG(delta_base_out);
 
        base_info = pack_window_open(p, w_curs, *curpos, &left);
        /* Assumption: the only reason this would fail is because the file is too small */
@@ -971,63 +1043,63 @@ int get_delta_base(
  *
  ***********************************************************/
 
-void git_packfile_close(struct git_pack_file *p, bool unlink_packfile)
+void git_packfile_free(struct git_pack_file *p, bool unlink_packfile)
 {
+       bool locked = true;
+
+       if (!p)
+               return;
+
+       cache_free(&p->bases);
+
+       if (git_mutex_lock(&p->lock) < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile");
+               locked = false;
+       }
        if (p->mwf.fd >= 0) {
-               git_mwindow_free_all_locked(&p->mwf);
+               git_mwindow_free_all(&p->mwf);
                p_close(p->mwf.fd);
                p->mwf.fd = -1;
        }
+       if (locked)
+               git_mutex_unlock(&p->lock);
 
        if (unlink_packfile)
                p_unlink(p->pack_name);
-}
-
-void git_packfile_free(struct git_pack_file *p)
-{
-       if (!p)
-               return;
-
-       cache_free(&p->bases);
-
-       git_packfile_close(p, false);
 
        pack_index_free(p);
 
        git__free(p->bad_object_sha1);
 
-       git_mutex_free(&p->lock);
        git_mutex_free(&p->bases.lock);
+       git_mutex_free(&p->mwf.lock);
+       git_mutex_free(&p->lock);
        git__free(p);
 }
 
-static int packfile_open(struct git_pack_file *p)
+/* Run with the packfile and mwf locks held */
+static int packfile_open_locked(struct git_pack_file *p)
 {
        struct stat st;
        struct git_pack_header hdr;
        git_oid sha1;
        unsigned char *idx_sha1;
 
-       if (p->index_version == -1 && pack_index_open(p) < 0)
+       if (pack_index_open_locked(p) < 0)
                return git_odb__error_notfound("failed to open packfile", NULL, 0);
 
-       /* if mwf opened by another thread, return now */
-       if (git_mutex_lock(&p->lock) < 0)
-               return packfile_error("failed to get lock for open");
-
-       if (p->mwf.fd >= 0) {
-               git_mutex_unlock(&p->lock);
+       if (p->mwf.fd >= 0)
                return 0;
-       }
 
        /* TODO: open with noatime */
        p->mwf.fd = git_futils_open_ro(p->pack_name);
        if (p->mwf.fd < 0)
                goto cleanup;
 
-       if (p_fstat(p->mwf.fd, &st) < 0 ||
-               git_mwindow_file_register(&p->mwf) < 0)
+       if (p_fstat(p->mwf.fd, &st) < 0) {
+               git_error_set(GIT_ERROR_OS, "could not stat packfile");
                goto cleanup;
+       }
 
        /* If we created the struct before we had the pack we lack size. */
        if (!p->mwf.size) {
@@ -1058,8 +1130,7 @@ static int packfile_open(struct git_pack_file *p)
 
        /* Verify the pack matches its index. */
        if (p->num_objects != ntohl(hdr.hdr_entries) ||
-               p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1 ||
-               p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < 0)
+               p_pread(p->mwf.fd, sha1.id, GIT_OID_RAWSZ, p->mwf.size - GIT_OID_RAWSZ) < 0)
                goto cleanup;
 
        idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
@@ -1067,7 +1138,9 @@ static int packfile_open(struct git_pack_file *p)
        if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0)
                goto cleanup;
 
-       git_mutex_unlock(&p->lock);
+       if (git_mwindow_file_register(&p->mwf) < 0)
+               goto cleanup;
+
        return 0;
 
 cleanup:
@@ -1077,8 +1150,6 @@ cleanup:
                p_close(p->mwf.fd);
        p->mwf.fd = -1;
 
-       git_mutex_unlock(&p->lock);
-
        return -1;
 }
 
@@ -1148,13 +1219,22 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
        p->mtime = (git_time_t)st.st_mtime;
        p->index_version = -1;
 
-       if (git_mutex_init(&p->lock)) {
+       if (git_mutex_init(&p->lock) < 0) {
                git_error_set(GIT_ERROR_OS, "failed to initialize packfile mutex");
                git__free(p);
                return -1;
        }
 
+       if (git_mutex_init(&p->mwf.lock) < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to initialize packfile window mutex");
+               git_mutex_free(&p->lock);
+               git__free(p);
+               return -1;
+       }
+
        if (cache_init(&p->bases) < 0) {
+               git_mutex_free(&p->mwf.lock);
+               git_mutex_free(&p->lock);
                git__free(p);
                return -1;
        }
@@ -1170,28 +1250,29 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
  *
  ***********************************************************/
 
-static off64_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
+static off64_t nth_packed_object_offset_locked(struct git_pack_file *p, uint32_t n)
 {
-       const unsigned char *index = p->index_map.data;
-       const unsigned char *end = index + p->index_map.len;
+       const unsigned char *index, *end;
+       uint32_t off32;
+
+       index = p->index_map.data;
+       end = index + p->index_map.len;
        index += 4 * 256;
-       if (p->index_version == 1) {
+       if (p->index_version == 1)
                return ntohl(*((uint32_t *)(index + 24 * n)));
-       } else {
-               uint32_t off;
-               index += 8 + p->num_objects * (20 + 4);
-               off = ntohl(*((uint32_t *)(index + 4 * n)));
-               if (!(off & 0x80000000))
-                       return off;
-               index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
-
-               /* Make sure we're not being sent out of bounds */
-               if (index >= end - 8)
-                       return -1;
 
-               return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
-                                       ntohl(*((uint32_t *)(index + 4)));
-       }
+       index += 8 + p->num_objects * (20 + 4);
+       off32 = ntohl(*((uint32_t *)(index + 4 * n)));
+       if (!(off32 & 0x80000000))
+               return off32;
+       index += p->num_objects * 4 + (off32 & 0x7fffffff) * 8;
+
+       /* Make sure we're not being sent out of bounds */
+       if (index >= end - 8)
+               return -1;
+
+       return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
+                               ntohl(*((uint32_t *)(index + 4)));
 }
 
 static int git__memcmp4(const void *a, const void *b) {
@@ -1203,33 +1284,45 @@ int git_pack_foreach_entry(
        git_odb_foreach_cb cb,
        void *data)
 {
-       const unsigned char *index = p->index_map.data, *current;
+       const unsigned char *index, *current;
        uint32_t i;
        int error = 0;
+       git_array_oid_t oids = GIT_ARRAY_INIT;
+       git_oid *oid;
 
-       if (index == NULL) {
-               if ((error = pack_index_open(p)) < 0)
-                       return error;
+       if (git_mutex_lock(&p->lock) < 0)
+               return packfile_error("failed to get lock for git_pack_foreach_entry");
 
-               assert(p->index_map.data);
+       if ((error = pack_index_open_locked(p)) < 0) {
+               git_mutex_unlock(&p->lock);
+               return error;
+       }
 
-               index = p->index_map.data;
+       if (!p->index_map.data) {
+               git_error_set(GIT_ERROR_INTERNAL, "internal error: p->index_map.data == NULL");
+               git_mutex_unlock(&p->lock);
+               return -1;
        }
 
-       if (p->index_version > 1) {
+       index = p->index_map.data;
+
+       if (p->index_version > 1)
                index += 8;
-       }
 
        index += 4 * 256;
 
        if (p->oids == NULL) {
                git_vector offsets, oids;
 
-               if ((error = git_vector_init(&oids, p->num_objects, NULL)))
+               if ((error = git_vector_init(&oids, p->num_objects, NULL))) {
+                       git_mutex_unlock(&p->lock);
                        return error;
+               }
 
-               if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4)))
+               if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4))) {
+                       git_mutex_unlock(&p->lock);
                        return error;
+               }
 
                if (p->index_version > 1) {
                        const unsigned char *off = index + 24 * p->num_objects;
@@ -1250,10 +1343,104 @@ int git_pack_foreach_entry(
                p->oids = (git_oid **)git_vector_detach(NULL, NULL, &oids);
        }
 
-       for (i = 0; i < p->num_objects; i++)
-               if ((error = cb(p->oids[i], data)) != 0)
-                       return git_error_set_after_callback(error);
+       /* We need to copy the OIDs to another array before we relinquish the lock to avoid races. */
+       git_array_init_to_size(oids, p->num_objects);
+       if (!oids.ptr) {
+               git_mutex_unlock(&p->lock);
+               git_array_clear(oids);
+               GIT_ERROR_CHECK_ARRAY(oids);
+       }
+       for (i = 0; i < p->num_objects; i++) {
+               oid = git_array_alloc(oids);
+               if (!oid) {
+                       git_mutex_unlock(&p->lock);
+                       git_array_clear(oids);
+                       GIT_ERROR_CHECK_ALLOC(oid);
+               }
+               git_oid_cpy(oid, p->oids[i]);
+       }
+
+       git_mutex_unlock(&p->lock);
 
+       git_array_foreach(oids, i, oid) {
+               if ((error = cb(oid, data)) != 0) {
+                       git_error_set_after_callback(error);
+                       break;
+               }
+       }
+
+       git_array_clear(oids);
+       return error;
+}
+
+int git_pack_foreach_entry_offset(
+       struct git_pack_file *p,
+       git_pack_foreach_entry_offset_cb cb,
+       void *data)
+{
+       const unsigned char *index;
+       off64_t current_offset;
+       const git_oid *current_oid;
+       uint32_t i;
+       int error = 0;
+
+       if (git_mutex_lock(&p->lock) < 0)
+               return packfile_error("failed to get lock for git_pack_foreach_entry_offset");
+
+       index = p->index_map.data;
+       if (index == NULL) {
+               if ((error = pack_index_open_locked(p)) < 0)
+                       goto cleanup;
+
+               if (!p->index_map.data) {
+                       git_error_set(GIT_ERROR_INTERNAL, "internal error: p->index_map.data == NULL");
+                       goto cleanup;
+               }
+
+               index = p->index_map.data;
+       }
+
+       if (p->index_version > 1)
+               index += 8;
+
+       index += 4 * 256;
+
+       /* all offsets should have been validated by pack_index_check_locked */
+       if (p->index_version > 1) {
+               const unsigned char *offsets = index + 24 * p->num_objects;
+               const unsigned char *large_offset_ptr;
+               const unsigned char *large_offsets = index + 28 * p->num_objects;
+               const unsigned char *large_offsets_end = ((const unsigned char *)p->index_map.data) + p->index_map.len - 20;
+               for (i = 0; i < p->num_objects; i++) {
+                       current_offset = ntohl(*(const uint32_t *)(offsets + 4 * i));
+                       if (current_offset & 0x80000000) {
+                               large_offset_ptr = large_offsets + (current_offset & 0x7fffffff) * 8;
+                               if (large_offset_ptr >= large_offsets_end) {
+                                       error = packfile_error("invalid large offset");
+                                       goto cleanup;
+                               }
+                               current_offset = (((off64_t)ntohl(*((uint32_t *)(large_offset_ptr + 0)))) << 32) |
+                                               ntohl(*((uint32_t *)(large_offset_ptr + 4)));
+                       }
+                       current_oid = (const git_oid *)(index + 20 * i);
+                       if ((error = cb(current_oid, current_offset, data)) != 0) {
+                               error = git_error_set_after_callback(error);
+                               goto cleanup;
+                       }
+               }
+       } else {
+               for (i = 0; i < p->num_objects; i++) {
+                       current_offset = ntohl(*(const uint32_t *)(index + 24 * i));
+                       current_oid = (const git_oid *)(index + 24 * i + 4);
+                       if ((error = cb(current_oid, current_offset, data)) != 0) {
+                               error = git_error_set_after_callback(error);
+                               goto cleanup;
+                       }
+               }
+       }
+
+cleanup:
+       git_mutex_unlock(&p->lock);
        return error;
 }
 
@@ -1291,15 +1478,19 @@ static int pack_entry_find_offset(
        int pos, found = 0;
        off64_t offset;
        const unsigned char *current = 0;
+       int error = 0;
 
        *offset_out = 0;
 
-       if (p->index_version == -1) {
-               int error;
+       if (git_mutex_lock(&p->lock) < 0)
+               return packfile_error("failed to get lock for pack_entry_find_offset");
+
+       if ((error = pack_index_open_locked(p)) < 0)
+               goto cleanup;
 
-               if ((error = pack_index_open(p)) < 0)
-                       return error;
-               assert(p->index_map.data);
+       if (!p->index_map.data) {
+               git_error_set(GIT_ERROR_INTERNAL, "internal error: p->index_map.data == NULL");
+               goto cleanup;
        }
 
        index = p->index_map.data;
@@ -1353,14 +1544,19 @@ static int pack_entry_find_offset(
                }
        }
 
-       if (!found)
-               return git_odb__error_notfound("failed to find offset for pack entry", short_oid, len);
-       if (found > 1)
-               return git_odb__error_ambiguous("found multiple offsets for pack entry");
+       if (!found) {
+               error = git_odb__error_notfound("failed to find offset for pack entry", short_oid, len);
+               goto cleanup;
+       }
+       if (found > 1) {
+               error = git_odb__error_ambiguous("found multiple offsets for pack entry");
+               goto cleanup;
+       }
 
-       if ((offset = nth_packed_object_offset(p, pos)) < 0) {
+       if ((offset = nth_packed_object_offset_locked(p, pos)) < 0) {
                git_error_set(GIT_ERROR_ODB, "packfile index is corrupt");
-               return -1;
+               error = -1;
+               goto cleanup;
        }
 
        *offset_out = offset;
@@ -1375,7 +1571,9 @@ static int pack_entry_find_offset(
        }
 #endif
 
-       return 0;
+cleanup:
+       git_mutex_unlock(&p->lock);
+       return error;
 }
 
 int git_pack_entry_find(
@@ -1388,7 +1586,7 @@ int git_pack_entry_find(
        git_oid found_oid;
        int error;
 
-       assert(p);
+       GIT_ASSERT_ARG(p);
 
        if (len == GIT_OID_HEXSZ && p->num_bad_objects) {
                unsigned i;
@@ -1401,10 +1599,26 @@ int git_pack_entry_find(
        if (error < 0)
                return error;
 
+       error = git_mutex_lock(&p->lock);
+       if (error < 0) {
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               return error;
+       }
+       error = git_mutex_lock(&p->mwf.lock);
+       if (error < 0) {
+               git_mutex_unlock(&p->lock);
+               git_error_set(GIT_ERROR_OS, "failed to lock packfile reader");
+               return error;
+       }
+
        /* we found a unique entry in the index;
         * make sure the packfile backing the index
         * still exists on disk */
-       if (p->mwf.fd == -1 && (error = packfile_open(p)) < 0)
+       if (p->mwf.fd == -1)
+               error = packfile_open_locked(p);
+       git_mutex_unlock(&p->mwf.lock);
+       git_mutex_unlock(&p->lock);
+       if (error < 0)
                return error;
 
        e->offset = offset;
index cebfcd1bd2972dacc37e2532417cd2370c0bd407..bf279c6b6ac37d4109b2a6ac3b98396e0fa48a4d 100644 (file)
 #include "oidmap.h"
 #include "zstream.h"
 
+/**
+ * Function type for callbacks from git_pack_foreach_entry_offset.
+ */
+typedef int git_pack_foreach_entry_offset_cb(
+               const git_oid *id,
+               off64_t offset,
+               void *payload);
+
 #define GIT_PACK_FILE_MODE 0444
 
 #define PACK_SIGNATURE 0x5041434b      /* "PACK" */
@@ -58,7 +66,7 @@ struct git_pack_idx_header {
 
 typedef struct git_pack_cache_entry {
        size_t last_usage; /* enough? */
-       git_atomic refcount;
+       git_atomic32 refcount;
        git_rawobj raw;
 } git_pack_cache_entry;
 
@@ -85,8 +93,8 @@ typedef struct {
 struct git_pack_file {
        git_mwindow_file mwf;
        git_map index_map;
-       git_mutex lock; /* protect updates to mwf and index_map */
-       git_atomic refcount;
+       git_mutex lock; /* protect updates to index_map */
+       git_atomic32 refcount;
 
        uint32_t num_objects;
        uint32_t num_bad_objects;
@@ -133,14 +141,14 @@ typedef struct git_packfile_stream {
        git_mwindow *mw;
 } git_packfile_stream;
 
-size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_object_t type);
+int git_packfile__object_header(size_t *out, unsigned char *hdr, size_t size, git_object_t type);
 
 int git_packfile__name(char **out, const char *path);
 
 int git_packfile_unpack_header(
                size_t *size_p,
                git_object_t *type_p,
-               git_mwindow_file *mwf,
+               struct git_pack_file *p,
                git_mwindow **w_curs,
                off64_t *curpos);
 
@@ -164,8 +172,7 @@ int get_delta_base(
                git_object_t type,
                off64_t delta_obj_offset);
 
-void git_packfile_close(struct git_pack_file *p, bool unlink_packfile);
-void git_packfile_free(struct git_pack_file *p);
+void git_packfile_free(struct git_pack_file *p, bool unlink_packfile);
 int git_packfile_alloc(struct git_pack_file **pack_out, const char *path);
 
 int git_pack_entry_find(
@@ -177,5 +184,16 @@ int git_pack_foreach_entry(
                struct git_pack_file *p,
                git_odb_foreach_cb cb,
                void *data);
+/**
+ * Similar to git_pack_foreach_entry, but:
+ * - It also provides the offset of the object within the
+ *   packfile.
+ * - It does not sort the objects in any order.
+ * - It retains the lock while invoking the callback.
+ */
+int git_pack_foreach_entry_offset(
+               struct git_pack_file *p,
+               git_pack_foreach_entry_offset_cb cb,
+               void *data);
 
 #endif
index 82181bb3d9ed6252320073e203e9357e4f397ccc..f02c928de255e78742241d464bb1d1e3530b63b8 100644 (file)
@@ -65,7 +65,7 @@ size_t git_patch_size(
 {
        size_t out;
 
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
 
        out = patch->content_size;
 
@@ -129,13 +129,13 @@ int git_patch_line_stats(
 
 const git_diff_delta *git_patch_get_delta(const git_patch *patch)
 {
-       assert(patch);
+       GIT_ASSERT_ARG_WITH_RETVAL(patch, NULL);
        return patch->delta;
 }
 
 size_t git_patch_num_hunks(const git_patch *patch)
 {
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
        return git_array_size(patch->hunks);
 }
 
@@ -152,7 +152,7 @@ int git_patch_get_hunk(
        size_t hunk_idx)
 {
        git_patch_hunk *hunk;
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
 
        hunk = git_array_get(patch->hunks, hunk_idx);
 
@@ -170,7 +170,7 @@ int git_patch_get_hunk(
 int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx)
 {
        git_patch_hunk *hunk;
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
 
        if (!(hunk = git_array_get(patch->hunks, hunk_idx)))
                return patch_error_outofrange("hunk");
@@ -186,7 +186,7 @@ int git_patch_get_line_in_hunk(
        git_patch_hunk *hunk;
        git_diff_line *line;
 
-       assert(patch);
+       GIT_ASSERT_ARG(patch);
 
        if (!(hunk = git_array_get(patch->hunks, hunk_idx))) {
                if (out) *out = NULL;
@@ -204,9 +204,16 @@ int git_patch_get_line_in_hunk(
        return 0;
 }
 
+git_repository *git_patch_owner(const git_patch *patch)
+{
+       return patch->repo;
+}
+
 int git_patch_from_diff(git_patch **out, git_diff *diff, size_t idx)
 {
-       assert(out && diff && diff->patch_fn);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diff);
+       GIT_ASSERT_ARG(diff->patch_fn);
        return diff->patch_fn(out, diff, idx);
 }
 
index 6dd61c18f119892c8159e898de82213b77a2f2c8..38cd714a9804f067c2d3c903610e00d1c06f16b9 100644 (file)
@@ -561,7 +561,7 @@ static int patch_from_sources(
        patch_generated_with_delta *pd;
        git_xdiff_output xo;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
        *out = NULL;
 
        if ((error = patch_generated_with_delta_alloc(
@@ -840,7 +840,7 @@ static int patch_generated_line_cb(
        GIT_UNUSED(hunk_);
 
        hunk = git_array_last(patch->base.hunks);
-       assert(hunk); /* programmer error if no hunk is available */
+       GIT_ASSERT(hunk); /* programmer error if no hunk is available */
 
        line = git_array_alloc(patch->base.lines);
        GIT_ERROR_CHECK_ALLOC(line);
index 2bf94c2cb075bcb879a5c867475baecdef63807c..2cc5c5995171086bd2d5bbe716d957b0b4f384ea 100644 (file)
@@ -1168,7 +1168,8 @@ int git_patch_parse(
        size_t start, used;
        int error = 0;
 
-       assert(out && ctx);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ctx);
 
        *out = NULL;
 
index f271c532cd03088d663e2ae99ae5222d755451ce..c444b31a7716572960f4a5de17e945a5287d53b0 100644 (file)
@@ -274,24 +274,6 @@ size_t git_path_basename_offset(git_buf *buffer)
        return 0;
 }
 
-const char *git_path_topdir(const char *path)
-{
-       size_t len;
-       ssize_t i;
-
-       assert(path);
-       len = strlen(path);
-
-       if (!len || path[len - 1] != '/')
-               return NULL;
-
-       for (i = (ssize_t)len - 2; i >= 0; --i)
-               if (path[i] == '/')
-                       break;
-
-       return &path[i + 1];
-}
-
 int git_path_root(const char *path)
 {
        int offset = 0, prefix_len;
@@ -325,7 +307,9 @@ int git_path_root(const char *path)
 static void path_trim_slashes(git_buf *path)
 {
        int ceiling = git_path_root(path->ptr) + 1;
-       assert(ceiling >= 0);
+
+       if (ceiling < 0)
+               return;
 
        while (path->size > (size_t)ceiling) {
                if (path->ptr[path->size-1] != '/')
@@ -341,7 +325,8 @@ int git_path_join_unrooted(
 {
        ssize_t root;
 
-       assert(path && path_out);
+       GIT_ASSERT_ARG(path_out);
+       GIT_ASSERT_ARG(path);
 
        root = (ssize_t)git_path_root(path);
 
@@ -389,7 +374,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
 {
        char buf[GIT_PATH_MAX];
 
-       assert(path && path_out);
+       GIT_ASSERT_ARG(path_out);
+       GIT_ASSERT_ARG(path);
 
        /* construct path if needed */
        if (base != NULL && git_path_root(path) < 0) {
@@ -427,7 +413,7 @@ int git_path_to_dir(git_buf *path)
        return git_buf_oom(path) ? -1 : 0;
 }
 
-void git_path_string_to_dir(charpath, size_t size)
+void git_path_string_to_dir(char *path, size_t size)
 {
        size_t end = strlen(path);
 
@@ -440,7 +426,9 @@ void git_path_string_to_dir(char* path, size_t size)
 int git__percent_decode(git_buf *decoded_out, const char *input)
 {
        int len, hi, lo, i;
-       assert(decoded_out && input);
+
+       GIT_ASSERT_ARG(decoded_out);
+       GIT_ASSERT_ARG(input);
 
        len = (int)strlen(input);
        git_buf_clear(decoded_out);
@@ -501,7 +489,8 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
 {
        int offset;
 
-       assert(local_path_out && file_url);
+       GIT_ASSERT_ARG(local_path_out);
+       GIT_ASSERT_ARG(file_url);
 
        if ((offset = local_file_url_prefixlen(file_url)) < 0 ||
                file_url[offset] == '\0' || file_url[offset] == '/')
@@ -526,7 +515,8 @@ int git_path_walk_up(
        ssize_t stop = 0, scan;
        char oldc = '\0';
 
-       assert(path && cb);
+       GIT_ASSERT_ARG(path);
+       GIT_ASSERT_ARG(cb);
 
        if (ceiling != NULL) {
                if (git__prefixcmp(path->ptr, ceiling) == 0)
@@ -581,7 +571,7 @@ int git_path_walk_up(
 
 bool git_path_exists(const char *path)
 {
-       assert(path);
+       GIT_ASSERT_ARG_WITH_RETVAL(path, false);
        return p_access(path, F_OK) == 0;
 }
 
@@ -598,7 +588,7 @@ bool git_path_isfile(const char *path)
 {
        struct stat st;
 
-       assert(path);
+       GIT_ASSERT_ARG_WITH_RETVAL(path, false);
        if (p_stat(path, &st) < 0)
                return false;
 
@@ -609,7 +599,7 @@ bool git_path_islink(const char *path)
 {
        struct stat st;
 
-       assert(path);
+       GIT_ASSERT_ARG_WITH_RETVAL(path, false);
        if (p_lstat(path, &st) < 0)
                return false;
 
@@ -764,15 +754,13 @@ bool git_path_contains_file(git_buf *base, const char *file)
        return _check_dir_contents(base, file, &git_path_isfile);
 }
 
-int git_path_find_dir(git_buf *dir, const char *path, const char *base)
+int git_path_find_dir(git_buf *dir)
 {
-       int error = git_path_join_unrooted(dir, path, base, NULL);
+       int error = 0;
+       char buf[GIT_PATH_MAX];
 
-       if (!error) {
-               char buf[GIT_PATH_MAX];
-               if (p_realpath(dir->ptr, buf) != NULL)
-                       error = git_buf_sets(dir, buf);
-       }
+       if (p_realpath(dir->ptr, buf) != NULL)
+               error = git_buf_sets(dir, buf);
 
        /* call dirname if this is not a directory */
        if (!error) /* && git_path_isdir(dir->ptr) == false) */
@@ -1211,7 +1199,8 @@ int git_path_diriter_init(
        if (is_win7_or_later < 0)
                is_win7_or_later = git_has_win32_version(6, 1, 0);
 
-       assert(diriter && path);
+       GIT_ASSERT_ARG(diriter);
+       GIT_ASSERT_ARG(path);
 
        memset(diriter, 0, sizeof(git_path_diriter));
        diriter->handle = INVALID_HANDLE_VALUE;
@@ -1311,9 +1300,10 @@ int git_path_diriter_filename(
        size_t *out_len,
        git_path_diriter *diriter)
 {
-       assert(out && out_len && diriter);
-
-       assert(diriter->path_utf8.size > diriter->parent_utf8_len);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(out_len);
+       GIT_ASSERT_ARG(diriter);
+       GIT_ASSERT(diriter->path_utf8.size > diriter->parent_utf8_len);
 
        *out = &diriter->path_utf8.ptr[diriter->parent_utf8_len+1];
        *out_len = diriter->path_utf8.size - diriter->parent_utf8_len - 1;
@@ -1325,7 +1315,9 @@ int git_path_diriter_fullpath(
        size_t *out_len,
        git_path_diriter *diriter)
 {
-       assert(out && out_len && diriter);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(out_len);
+       GIT_ASSERT_ARG(diriter);
 
        *out = diriter->path_utf8.ptr;
        *out_len = diriter->path_utf8.size;
@@ -1334,7 +1326,8 @@ int git_path_diriter_fullpath(
 
 int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
 {
-       assert(out && diriter);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diriter);
 
        return git_win32__file_attribute_to_stat(out,
                (WIN32_FILE_ATTRIBUTE_DATA *)&diriter->current,
@@ -1361,7 +1354,8 @@ int git_path_diriter_init(
        const char *path,
        unsigned int flags)
 {
-       assert(diriter && path);
+       GIT_ASSERT_ARG(diriter);
+       GIT_ASSERT_ARG(path);
 
        memset(diriter, 0, sizeof(git_path_diriter));
 
@@ -1401,7 +1395,7 @@ int git_path_diriter_next(git_path_diriter *diriter)
        bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT);
        int error = 0;
 
-       assert(diriter);
+       GIT_ASSERT_ARG(diriter);
 
        errno = 0;
 
@@ -1444,9 +1438,10 @@ int git_path_diriter_filename(
        size_t *out_len,
        git_path_diriter *diriter)
 {
-       assert(out && out_len && diriter);
-
-       assert(diriter->path.size > diriter->parent_len);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(out_len);
+       GIT_ASSERT_ARG(diriter);
+       GIT_ASSERT(diriter->path.size > diriter->parent_len);
 
        *out = &diriter->path.ptr[diriter->parent_len+1];
        *out_len = diriter->path.size - diriter->parent_len - 1;
@@ -1458,7 +1453,9 @@ int git_path_diriter_fullpath(
        size_t *out_len,
        git_path_diriter *diriter)
 {
-       assert(out && out_len && diriter);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(out_len);
+       GIT_ASSERT_ARG(diriter);
 
        *out = diriter->path.ptr;
        *out_len = diriter->path.size;
@@ -1467,7 +1464,8 @@ int git_path_diriter_fullpath(
 
 int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
 {
-       assert(out && diriter);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(diriter);
 
        return git_path_lstat(diriter->path.ptr, out);
 }
@@ -1503,7 +1501,8 @@ int git_path_dirload(
        char *dup;
        int error;
 
-       assert(contents && path);
+       GIT_ASSERT_ARG(contents);
+       GIT_ASSERT_ARG(path);
 
        if ((error = git_path_diriter_init(&iter, path, flags)) < 0)
                return error;
@@ -1512,7 +1511,7 @@ int git_path_dirload(
                if ((error = git_path_diriter_fullpath(&name, &name_len, &iter)) < 0)
                        break;
 
-               assert(name_len > prefix_len);
+               GIT_ASSERT(name_len > prefix_len);
 
                dup = git__strndup(name + prefix_len, name_len - prefix_len);
                GIT_ERROR_CHECK_ALLOC(dup);
@@ -1561,8 +1560,8 @@ GIT_INLINE(bool) verify_dospath(
 static int32_t next_hfs_char(const char **in, size_t *len)
 {
        while (*len) {
-               int32_t codepoint;
-               int cp_len = git__utf8_iterate((const uint8_t *)(*in), (int)(*len), &codepoint);
+               uint32_t codepoint;
+               int cp_len = git_utf8_iterate(&codepoint, *in, *len);
                if (cp_len < 0)
                        return -1;
 
@@ -1594,7 +1593,7 @@ static int32_t next_hfs_char(const char **in, size_t *len)
                 * the ASCII range, which is perfectly fine, because the
                 * git folder name can only be composed of ascii characters
                 */
-               return git__tolower(codepoint);
+               return git__tolower((int)codepoint);
        }
        return 0; /* NULL byte -- end of string */
 }
@@ -1876,7 +1875,7 @@ GIT_INLINE(unsigned int) dotgit_flags(
        return flags;
 }
 
-bool git_path_isvalid(
+bool git_path_validate(
        git_repository *repo,
        const char *path,
        uint16_t mode,
@@ -1903,6 +1902,52 @@ bool git_path_isvalid(
        return verify_component(repo, start, (c - start), mode, flags);
 }
 
+#ifdef GIT_WIN32
+GIT_INLINE(bool) should_validate_longpaths(git_repository *repo)
+{
+       int longpaths = 0;
+
+       if (repo &&
+           git_repository__configmap_lookup(&longpaths, repo, GIT_CONFIGMAP_LONGPATHS) < 0)
+               longpaths = 0;
+
+       return (longpaths == 0);
+}
+
+#else
+
+GIT_INLINE(bool) should_validate_longpaths(git_repository *repo)
+{
+       GIT_UNUSED(repo);
+
+       return false;
+}
+#endif
+
+int git_path_validate_workdir(git_repository *repo, const char *path)
+{
+       if (should_validate_longpaths(repo))
+               return git_path_validate_filesystem(path, strlen(path));
+
+       return 0;
+}
+
+int git_path_validate_workdir_with_len(
+       git_repository *repo,
+       const char *path,
+       size_t path_len)
+{
+       if (should_validate_longpaths(repo))
+               return git_path_validate_filesystem(path, path_len);
+
+       return 0;
+}
+
+int git_path_validate_workdir_buf(git_repository *repo, git_buf *path)
+{
+       return git_path_validate_workdir_with_len(repo, path->ptr, path->size);
+}
+
 int git_path_normalize_slashes(git_buf *out, const char *path)
 {
        int error;
index ed6b93574f086e07b705b92a78b2497bc78162c6..de6ec8ff2483ab8f567934a88f3b83a6f918848f 100644 (file)
@@ -67,8 +67,6 @@ extern int git_path_basename_r(git_buf *buffer, const char *path);
  */
 extern size_t git_path_basename_offset(git_buf *buffer);
 
-extern const char *git_path_topdir(const char *path);
-
 /**
  * Find offset to root of path if path has one.
  *
@@ -87,7 +85,7 @@ extern int git_path_to_dir(git_buf *path);
 /**
  * Ensure string has a trailing '/' if there is space for it.
  */
-extern void git_path_string_to_dir(charpath, size_t size);
+extern void git_path_string_to_dir(char *path, size_t size);
 
 /**
  * Taken from git.git; returns nonzero if the given path is "." or "..".
@@ -285,7 +283,7 @@ extern int git_path_prettify_dir(git_buf *path_out, const char *path, const char
  * appends the trailing '/'.  If the path does not exist, it is
  * treated like a regular filename.
  */
-extern int git_path_find_dir(git_buf *dir, const char *path, const char *base);
+extern int git_path_find_dir(git_buf *dir);
 
 /**
  * Resolve relative references within a path.
@@ -628,20 +626,95 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
 #define GIT_PATH_REJECT_INDEX_DEFAULTS \
        GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT
 
-/*
- * Determine whether a path is a valid git path or not - this must not contain
+/**
+ * Validate a "bare" git path.  This ensures that the given path is legal
+ * to place in the index or a tree.  This should be checked by mechanisms
+ * like `git_index_add` and `git_treebuilder_insert` when taking user
+ * data, and by `git_checkout` before constructing on-disk paths.
+ *
+ * This will ensure that a git path does not contain any "unsafe" components,
  * a '.' or '..' component, or a component that is ".git" (in any case).
  *
+ * (Note: if you take or construct an on-disk path -- a workdir path,
+ * a path to a git repository or a reference name that could be a loose
+ * ref -- you should _also_ validate that with `git_path_validate_workdir`.)
+ *
  * `repo` is optional.  If specified, it will be used to determine the short
  * path name to reject (if `GIT_PATH_REJECT_DOS_SHORTNAME` is specified),
  * in addition to the default of "git~1".
  */
-extern bool git_path_isvalid(
+extern bool git_path_validate(
        git_repository *repo,
        const char *path,
        uint16_t mode,
        unsigned int flags);
 
+/**
+ * Validate an on-disk path, taking into account that it will have a
+ * suffix appended (eg, `.lock`).
+ */
+GIT_INLINE(int) git_path_validate_filesystem_with_suffix(
+       const char *path,
+       size_t path_len,
+       size_t suffix_len)
+{
+#ifdef GIT_WIN32
+       size_t path_chars, total_chars;
+
+       path_chars = git_utf8_char_length(path, path_len);
+
+       if (GIT_ADD_SIZET_OVERFLOW(&total_chars, path_chars, suffix_len) ||
+           total_chars > MAX_PATH) {
+               git_error_set(GIT_ERROR_FILESYSTEM, "path too long: '%s'", path);
+               return -1;
+       }
+       return 0;
+#else
+       GIT_UNUSED(path);
+       GIT_UNUSED(path_len);
+       GIT_UNUSED(suffix_len);
+       return 0;
+#endif
+}
+
+/**
+ * Validate an path on the filesystem.  This ensures that the given
+ * path is valid for the operating system/platform; for example, this
+ * will ensure that the given absolute path is smaller than MAX_PATH on
+ * Windows.
+ *
+ * For paths within the working directory, you should use ensure that
+ * `core.longpaths` is obeyed.  Use `git_path_validate_workdir`.
+ */
+GIT_INLINE(int) git_path_validate_filesystem(
+       const char *path,
+       size_t path_len)
+{
+       return git_path_validate_filesystem_with_suffix(path, path_len, 0);
+}
+
+/**
+ * Validate a path relative to the repo's worktree.  This ensures that
+ * the given working tree path is valid for the operating system/platform.
+ * This will ensure that an absolute path is smaller than MAX_PATH on
+ * Windows, while keeping `core.longpaths` configuration settings in mind.
+ *
+ * This should be checked by mechamisms like `git_checkout` after
+ * contructing on-disk paths and before trying to write them.
+ *
+ * If the repository is null, no repository configuration is applied.
+ */
+extern int git_path_validate_workdir(
+       git_repository *repo,
+       const char *path);
+extern int git_path_validate_workdir_with_len(
+       git_repository *repo,
+       const char *path,
+       size_t path_len);
+extern int git_path_validate_workdir_buf(
+       git_repository *repo,
+       git_buf *buf);
+
 /**
  * Convert any backslashes into slashes
  */
index 83f776c91db27ce6c5908d54b6dd3a979052db84..c6ad16571ecaad30d5008d98d152ed8186286fbe 100644 (file)
@@ -9,7 +9,6 @@
 
 #include "git2/pathspec.h"
 #include "git2/diff.h"
-#include "buf_text.h"
 #include "attr_file.h"
 #include "iterator.h"
 #include "repository.h"
@@ -25,7 +24,7 @@ char *git_pathspec_prefix(const git_strarray *pathspec)
        const char *scan;
 
        if (!pathspec || !pathspec->count ||
-               git_buf_text_common_prefix(&prefix, pathspec) < 0)
+               git_buf_common_prefix(&prefix, pathspec->strings, pathspec->count) < 0)
                return NULL;
 
        /* diff prefix will only be leading non-wildcards */
@@ -41,7 +40,7 @@ char *git_pathspec_prefix(const git_strarray *pathspec)
                return NULL;
        }
 
-       git_buf_text_unescape(&prefix);
+       git_buf_unescape(&prefix);
 
        return git_buf_detach(&prefix);
 }
@@ -289,7 +288,8 @@ int git_pathspec_matches_path(
        bool no_fnmatch = (flags & GIT_PATHSPEC_NO_GLOB) != 0;
        bool casefold =  (flags & GIT_PATHSPEC_IGNORE_CASE) != 0;
 
-       assert(ps && path);
+       GIT_ASSERT_ARG(ps);
+       GIT_ASSERT_ARG(path);
 
        return (0 != git_pathspec__match(
                &ps->pathspec, path, no_fnmatch, casefold, NULL, NULL));
@@ -526,7 +526,7 @@ int git_pathspec_match_workdir(
        git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
        int error = 0;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        iter_opts.flags = pathspec_match_iter_flags(flags);
 
@@ -548,7 +548,7 @@ int git_pathspec_match_index(
        git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
        int error = 0;
 
-       assert(index);
+       GIT_ASSERT_ARG(index);
 
        iter_opts.flags = pathspec_match_iter_flags(flags);
 
@@ -570,7 +570,7 @@ int git_pathspec_match_tree(
        git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
        int error = 0;
 
-       assert(tree);
+       GIT_ASSERT_ARG(tree);
 
        iter_opts.flags = pathspec_match_iter_flags(flags);
 
@@ -598,7 +598,7 @@ int git_pathspec_match_diff(
        const git_diff_delta *delta, **match;
        git_bitvec used_patterns;
 
-       assert(diff);
+       GIT_ASSERT_ARG(diff);
 
        if (git_bitvec_init(&used_patterns, patterns->length) < 0)
                return -1;
index 0c423dd3a6cc6765b4c18b230c7bb4916cfa9865..16ffa398d65d08a60c69d7c21414252a51675b77 100644 (file)
@@ -36,8 +36,8 @@ int git_pool_global_init(void)
 
 int git_pool_init(git_pool *pool, size_t item_size)
 {
-       assert(pool);
-       assert(item_size >= 1);
+       GIT_ASSERT_ARG(pool);
+       GIT_ASSERT_ARG(item_size >= 1);
 
        memset(pool, 0, sizeof(git_pool));
        pool->item_size = item_size;
@@ -131,8 +131,8 @@ static int git_pool__ptr_cmp(const void * a, const void * b)
 
 int git_pool_init(git_pool *pool, size_t item_size)
 {
-       assert(pool);
-       assert(item_size >= 1);
+       GIT_ASSERT_ARG(pool);
+       GIT_ASSERT_ARG(item_size >= 1);
 
        memset(pool, 0, sizeof(git_pool));
        pool->item_size = item_size;
@@ -205,7 +205,9 @@ char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
 {
        char *ptr = NULL;
 
-       assert(pool && str && pool->item_size == sizeof(char));
+       GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
 
        if (n == SIZE_MAX)
                return NULL;
@@ -220,7 +222,10 @@ char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
 
 char *git_pool_strdup(git_pool *pool, const char *str)
 {
-       assert(pool && str && pool->item_size == sizeof(char));
+       GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
+
        return git_pool_strndup(pool, str, strlen(str));
 }
 
@@ -234,7 +239,8 @@ char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
        void *ptr;
        size_t len_a, len_b, total;
 
-       assert(pool && pool->item_size == sizeof(char));
+       GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
 
        len_a = a ? strlen(a) : 0;
        len_b = b ? strlen(b) : 0;
index fbaa7c3caab82be0e76f4ea00023685060c3488a..c40134824a4a38f43cca6ecb0cc885af5c726770 100644 (file)
@@ -109,6 +109,13 @@ int p_open(const char *path, volatile int flags, ...)
 {
        mode_t mode = 0;
 
+       #ifdef GIT_DEBUG_STRICT_OPEN
+       if (strstr(path, "//") != NULL) {
+               errno = EACCES;
+               return -1;
+       }
+       #endif
+
        if (flags & O_CREAT) {
                va_list arg_list;
 
@@ -129,7 +136,8 @@ int p_getcwd(char *buffer_out, size_t size)
 {
        char *cwd_buffer;
 
-       assert(buffer_out && size > 0);
+       GIT_ASSERT_ARG(buffer_out);
+       GIT_ASSERT_ARG(size > 0);
 
        cwd_buffer = getcwd(buffer_out, size);
 
@@ -196,7 +204,7 @@ int p_write(git_file fd, const void *buf, size_t cnt)
        while (cnt) {
                ssize_t r;
 #ifdef GIT_WIN32
-               assert((size_t)((unsigned int)cnt) == cnt);
+               GIT_ASSERT((size_t)((unsigned int)cnt) == cnt);
                r = write(fd, b, (unsigned int)cnt);
 #else
                r = write(fd, b, cnt);
@@ -237,24 +245,43 @@ int git__mmap_alignment(size_t *alignment)
 
 int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
 {
+       const char *ptr;
+       size_t remaining_len;
+
        GIT_MMAP_VALIDATE(out, len, prot, flags);
 
-       out->data = NULL;
-       out->len = 0;
+       /* writes cannot be emulated without handling pagefaults since write happens by
+        * writing to mapped memory */
+       if (prot & GIT_PROT_WRITE) {
+               git_error_set(GIT_ERROR_OS, "trying to map %s-writeable",
+                               ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private");
+               return -1;
+       }
 
-       if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
-               git_error_set(GIT_ERROR_OS, "trying to map shared-writeable");
+       if (!git__is_ssizet(len)) {
+               errno = EINVAL;
                return -1;
        }
 
+       out->len = 0;
        out->data = git__malloc(len);
        GIT_ERROR_CHECK_ALLOC(out->data);
 
-       if (!git__is_ssizet(len) ||
-               (p_lseek(fd, offset, SEEK_SET) < 0) ||
-               (p_read(fd, out->data, len) != (ssize_t)len)) {
-               git_error_set(GIT_ERROR_OS, "mmap emulation failed");
-               return -1;
+       remaining_len = len;
+       ptr = (const char *)out->data;
+       while (remaining_len > 0) {
+               ssize_t nb;
+               HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset));
+               if (nb <= 0) {
+                       git_error_set(GIT_ERROR_OS, "mmap emulation failed");
+                       git__free(out->data);
+                       out->data = NULL;
+                       return -1;
+               }
+
+               ptr += nb;
+               offset += nb;
+               remaining_len -= nb;
        }
 
        out->len = len;
@@ -263,9 +290,13 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset
 
 int p_munmap(git_map *map)
 {
-       assert(map != NULL);
+       GIT_ASSERT_ARG(map);
        git__free(map->data);
 
+       /* Initializing will help debug use-after-free */
+       map->len = 0;
+       map->data = NULL;
+
        return 0;
 }
 
index eef667762cfa2cf15c78a0725c2171e8f446002c..d98bc82ca80c1bbc2e22087a1876a54cb72f1b83 100644 (file)
 #define EAFNOSUPPORT (INT_MAX-1)
 #endif
 
+/* Compiler independent macro to handle signal interrpted system calls */
+#define HANDLE_EINTR(result, x) do {                                   \
+               result = (x);                                           \
+       } while (result == -1 && errno == EINTR);
+
+
 /* Provide a 64-bit size for offsets. */
 
 #if defined(_MSC_VER)
@@ -119,6 +125,9 @@ typedef int git_file;
 extern ssize_t p_read(git_file fd, void *buf, size_t cnt);
 extern int p_write(git_file fd, const void *buf, size_t cnt);
 
+extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset);
+extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset);
+
 #define p_close(fd) close(fd)
 #define p_umask(m) umask(m)
 
index 90f700a001134d8329ca7c5632438a4fe0117520..48928940dbc7f1ff52558513d812cb170162b6f9 100644 (file)
@@ -61,7 +61,8 @@ int git_reader_for_tree(git_reader **out, git_tree *tree)
 {
        tree_reader *reader;
 
-       assert(out && tree);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(tree);
 
        reader = git__calloc(1, sizeof(tree_reader));
        GIT_ERROR_CHECK_ALLOC(reader);
@@ -97,8 +98,7 @@ static int workdir_reader_read(
        git_oid id;
        int error;
 
-       if ((error = git_buf_joinpath(&path,
-               git_repository_workdir(reader->repo), filename)) < 0)
+       if ((error = git_repository_workdir_path(&path, reader->repo, filename)) < 0)
                goto done;
 
        if ((error = p_lstat(path.ptr, &st)) < 0) {
@@ -158,7 +158,8 @@ int git_reader_for_workdir(
        workdir_reader *reader;
        int error;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        reader = git__calloc(1, sizeof(workdir_reader));
        GIT_ERROR_CHECK_ALLOC(reader);
@@ -223,7 +224,8 @@ int git_reader_for_index(
        index_reader *reader;
        int error;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        reader = git__calloc(1, sizeof(index_reader));
        GIT_ERROR_CHECK_ALLOC(reader);
@@ -251,7 +253,9 @@ int git_reader_read(
        git_reader *reader,
        const char *filename)
 {
-       assert(out && reader && filename);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(reader);
+       GIT_ASSERT_ARG(filename);
 
        return reader->read(out, out_id, out_filemode, reader, filename);
 }
index 7c6561195630ebbe6c0321d392f312591d8551cf..4f10c296bdd294e6ee802965cae0a1cbb74bdf85 100644 (file)
@@ -186,8 +186,8 @@ static git_rebase_operation *rebase_operation_alloc(
 {
        git_rebase_operation *operation;
 
-       assert((type == GIT_REBASE_OPERATION_EXEC) == !id);
-       assert((type == GIT_REBASE_OPERATION_EXEC) == !!exec);
+       GIT_ASSERT_WITH_RETVAL((type == GIT_REBASE_OPERATION_EXEC) == !id, NULL);
+       GIT_ASSERT_WITH_RETVAL((type == GIT_REBASE_OPERATION_EXEC) == !!exec, NULL);
 
        if ((operation = git_array_alloc(rebase->operations)) == NULL)
                return NULL;
@@ -301,7 +301,7 @@ int git_rebase_open(
        size_t state_path_len;
        int error;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        if ((error = rebase_check_versions(given_opts)) < 0)
                return error;
@@ -701,7 +701,8 @@ int git_rebase_init(
        bool inmemory = (given_opts && given_opts->inmemory);
        int error;
 
-       assert(repo && (upstream || onto));
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(upstream || onto);
 
        *out = NULL;
 
@@ -912,7 +913,8 @@ int git_rebase_next(
 {
        int error;
 
-       assert(out && rebase);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(rebase);
 
        if ((error = rebase_movenext(rebase)) < 0)
                return error;
@@ -931,7 +933,9 @@ int git_rebase_inmemory_index(
        git_index **out,
        git_rebase *rebase)
 {
-       assert(out && rebase && rebase->index);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(rebase);
+       GIT_ASSERT_ARG(rebase->index);
 
        GIT_REFCOUNT_INC(rebase->index);
        *out = rebase->index;
@@ -939,6 +943,54 @@ int git_rebase_inmemory_index(
        return 0;
 }
 
+#ifndef GIT_DEPRECATE_HARD
+static int create_signed(
+       git_oid *out,
+       git_rebase *rebase,
+       const git_signature *author,
+       const git_signature *committer,
+       const char *message_encoding,
+       const char *message,
+       git_tree *tree,
+       size_t parent_count,
+       const git_commit **parents)
+{
+       git_buf commit_content = GIT_BUF_INIT,
+               commit_signature = GIT_BUF_INIT,
+               signature_field = GIT_BUF_INIT;
+       int error;
+
+       git_error_clear();
+
+       if ((error = git_commit_create_buffer(&commit_content,
+               rebase->repo, author, committer, message_encoding,
+               message, tree, parent_count, parents)) < 0)
+               goto done;
+
+       error = rebase->options.signing_cb(&commit_signature,
+               &signature_field, commit_content.ptr,
+               rebase->options.payload);
+
+       if (error) {
+               if (error != GIT_PASSTHROUGH)
+                       git_error_set_after_callback_function(error, "signing_cb");
+
+               goto done;
+       }
+
+       error = git_commit_create_with_signature(out, rebase->repo,
+               commit_content.ptr,
+               commit_signature.size > 0 ? commit_signature.ptr : NULL,
+               signature_field.size > 0 ? signature_field.ptr : NULL);
+
+done:
+       git_buf_dispose(&commit_signature);
+       git_buf_dispose(&signature_field);
+       git_buf_dispose(&commit_content);
+       return error;
+}
+#endif
+
 static int rebase_commit__create(
        git_commit **out,
        git_rebase *rebase,
@@ -953,10 +1005,6 @@ static int rebase_commit__create(
        git_commit *current_commit = NULL, *commit = NULL;
        git_tree *parent_tree = NULL, *tree = NULL;
        git_oid tree_id, commit_id;
-       git_buf commit_content = GIT_BUF_INIT, commit_signature = GIT_BUF_INIT,
-               signature_field = GIT_BUF_INIT;
-       const char *signature_field_string = NULL,
-               *commit_signature_string = NULL;
        int error;
 
        operation = git_array_get(rebase->operations, rebase->current);
@@ -987,37 +1035,32 @@ static int rebase_commit__create(
                message = git_commit_message(current_commit);
        }
 
-       if ((error = git_commit_create_buffer(&commit_content, rebase->repo, author, committer,
-                       message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0)
-               goto done;
+       git_error_clear();
+       error = GIT_PASSTHROUGH;
 
-       if (rebase->options.signing_cb) {
-               git_error_clear();
-               error = git_error_set_after_callback_function(rebase->options.signing_cb(
-                       &commit_signature, &signature_field, git_buf_cstr(&commit_content),
-                       rebase->options.payload), "commit signing_cb failed");
-               if (error == GIT_PASSTHROUGH) {
-                       git_buf_dispose(&commit_signature);
-                       git_buf_dispose(&signature_field);
-                       git_error_clear();
-                       error = GIT_OK;
-               } else if (error < 0)
-                       goto done;
-       }
+       if (rebase->options.commit_create_cb) {
+               error = rebase->options.commit_create_cb(&commit_id,
+                       author, committer, message_encoding, message,
+                       tree, 1, (const git_commit **)&parent_commit,
+                       rebase->options.payload);
 
-       if (git_buf_is_allocated(&commit_signature)) {
-               assert(git_buf_contains_nul(&commit_signature));
-               commit_signature_string = git_buf_cstr(&commit_signature);
+               git_error_set_after_callback_function(error,
+                       "commit_create_cb");
        }
-
-       if (git_buf_is_allocated(&signature_field)) {
-               assert(git_buf_contains_nul(&signature_field));
-               signature_field_string = git_buf_cstr(&signature_field);
+#ifndef GIT_DEPRECATE_HARD
+       else if (rebase->options.signing_cb) {
+               error = create_signed(&commit_id, rebase, author,
+                       committer, message_encoding, message, tree,
+                       1, (const git_commit **)&parent_commit);
        }
+#endif
 
-       if ((error = git_commit_create_with_signature(&commit_id, rebase->repo,
-                       git_buf_cstr(&commit_content), commit_signature_string,
-                       signature_field_string)))
+       if (error == GIT_PASSTHROUGH)
+               error = git_commit_create(&commit_id, rebase->repo, NULL,
+                       author, committer, message_encoding, message,
+                       tree, 1, (const git_commit **)&parent_commit);
+
+       if (error)
                goto done;
 
        if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
@@ -1029,9 +1072,6 @@ done:
        if (error < 0)
                git_commit_free(commit);
 
-       git_buf_dispose(&commit_signature);
-       git_buf_dispose(&signature_field);
-       git_buf_dispose(&commit_content);
        git_commit_free(current_commit);
        git_tree_free(parent_tree);
        git_tree_free(tree);
@@ -1055,7 +1095,7 @@ static int rebase_commit_merge(
        int error;
 
        operation = git_array_get(rebase->operations, rebase->current);
-       assert(operation);
+       GIT_ASSERT(operation);
 
        if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 ||
                (error = git_repository_head(&head, rebase->repo)) < 0 ||
@@ -1095,9 +1135,9 @@ static int rebase_commit_inmemory(
        git_commit *commit = NULL;
        int error = 0;
 
-       assert(rebase->index);
-       assert(rebase->last_commit);
-       assert(rebase->current < rebase->operations.size);
+       GIT_ASSERT_ARG(rebase->index);
+       GIT_ASSERT_ARG(rebase->last_commit);
+       GIT_ASSERT_ARG(rebase->current < rebase->operations.size);
 
        if ((error = rebase_commit__create(&commit, rebase, rebase->index,
                rebase->last_commit, author, committer, message_encoding, message)) < 0)
@@ -1125,7 +1165,8 @@ int git_rebase_commit(
 {
        int error;
 
-       assert(rebase && committer);
+       GIT_ASSERT_ARG(rebase);
+       GIT_ASSERT_ARG(committer);
 
        if (rebase->inmemory)
                error = rebase_commit_inmemory(
@@ -1145,7 +1186,7 @@ int git_rebase_abort(git_rebase *rebase)
        git_commit *orig_head_commit = NULL;
        int error;
 
-       assert(rebase);
+       GIT_ASSERT_ARG(rebase);
 
        if (rebase->inmemory)
                return 0;
@@ -1358,7 +1399,7 @@ int git_rebase_finish(
 {
        int error = 0;
 
-       assert(rebase);
+       GIT_ASSERT_ARG(rebase);
 
        if (rebase->inmemory)
                return 0;
@@ -1373,14 +1414,17 @@ int git_rebase_finish(
 }
 
 const char *git_rebase_orig_head_name(git_rebase *rebase) {
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, NULL);
        return rebase->orig_head_name;
 }
 
 const git_oid *git_rebase_orig_head_id(git_rebase *rebase) {
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, NULL);
        return &rebase->orig_head_id;
 }
 
 const char *git_rebase_onto_name(git_rebase *rebase) {
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, NULL);
        return rebase->onto_name;
 }
 
@@ -1390,21 +1434,21 @@ const git_oid *git_rebase_onto_id(git_rebase *rebase) {
 
 size_t git_rebase_operation_entrycount(git_rebase *rebase)
 {
-       assert(rebase);
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, 0);
 
        return git_array_size(rebase->operations);
 }
 
 size_t git_rebase_operation_current(git_rebase *rebase)
 {
-       assert(rebase);
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, 0);
 
        return rebase->started ? rebase->current : GIT_REBASE_NO_OPERATION;
 }
 
 git_rebase_operation *git_rebase_operation_byindex(git_rebase *rebase, size_t idx)
 {
-       assert(rebase);
+       GIT_ASSERT_ARG_WITH_RETVAL(rebase, NULL);
 
        return git_array_get(rebase->operations, idx);
 }
index fb86d5ccbad15e14984ecccf10d9a40b120d955e..ed33de92bf2c1583f0a720e21f4aef7357d64e91 100644 (file)
@@ -24,7 +24,8 @@ int git_refdb_new(git_refdb **out, git_repository *repo)
 {
        git_refdb *db;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        db = git__calloc(1, sizeof(*db));
        GIT_ERROR_CHECK_ALLOC(db);
@@ -41,7 +42,8 @@ int git_refdb_open(git_refdb **out, git_repository *repo)
        git_refdb *db;
        git_refdb_backend *dir;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        *out = NULL;
 
@@ -89,7 +91,7 @@ int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
 
 int git_refdb_compress(git_refdb *db)
 {
-       assert(db);
+       GIT_ASSERT_ARG(db);
 
        if (db->backend->compress)
                return db->backend->compress(db->backend);
@@ -114,7 +116,9 @@ void git_refdb_free(git_refdb *db)
 
 int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
 {
-       assert(exists && refdb && refdb->backend);
+       GIT_ASSERT_ARG(exists);
+       GIT_ASSERT_ARG(refdb);
+       GIT_ASSERT_ARG(refdb->backend);
 
        return refdb->backend->exists(exists, refdb->backend, ref_name);
 }
@@ -124,7 +128,10 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
        git_reference *ref;
        int error;
 
-       assert(db && db->backend && out && ref_name);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(db->backend);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ref_name);
 
        error = db->backend->lookup(&ref, db->backend, ref_name);
        if (error < 0)
@@ -234,7 +241,8 @@ void git_refdb_iterator_free(git_reference_iterator *iter)
 
 int git_refdb_write(git_refdb *db, git_reference *ref, int force, const git_signature *who, const char *message, const git_oid *old_id, const char *old_target)
 {
-       assert(db && db->backend);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(db->backend);
 
        GIT_REFCOUNT_INC(db);
        ref->db = db;
@@ -253,7 +261,9 @@ int git_refdb_rename(
 {
        int error;
 
-       assert(db && db->backend);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(db->backend);
+
        error = db->backend->rename(out, db->backend, old_name, new_name, force, who, message);
        if (error < 0)
                return error;
@@ -268,7 +278,9 @@ int git_refdb_rename(
 
 int git_refdb_delete(struct git_refdb *db, const char *ref_name, const git_oid *old_id, const char *old_target)
 {
-       assert(db && db->backend);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(db->backend);
+
        return db->backend->del(db->backend, ref_name, old_id, old_target);
 }
 
@@ -276,7 +288,8 @@ int git_refdb_reflog_read(git_reflog **out, git_refdb *db,  const char *name)
 {
        int error;
 
-       assert(db && db->backend);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(db->backend);
 
        if ((error = db->backend->reflog_read(out, db->backend, name)) < 0)
                return error;
@@ -368,14 +381,16 @@ out:
 
 int git_refdb_has_log(git_refdb *db, const char *refname)
 {
-       assert(db && refname);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(refname);
 
        return db->backend->has_log(db->backend, refname);
 }
 
 int git_refdb_ensure_log(git_refdb *db, const char *refname)
 {
-       assert(db && refname);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(refname);
 
        return db->backend->ensure_log(db->backend, refname);
 }
@@ -389,7 +404,9 @@ int git_refdb_init_backend(git_refdb_backend *backend, unsigned int version)
 
 int git_refdb_lock(void **payload, git_refdb *db, const char *refname)
 {
-       assert(payload && db && refname);
+       GIT_ASSERT_ARG(payload);
+       GIT_ASSERT_ARG(db);
+       GIT_ASSERT_ARG(refname);
 
        if (!db->backend->lock) {
                git_error_set(GIT_ERROR_REFERENCE, "backend does not support locking");
@@ -401,7 +418,7 @@ int git_refdb_lock(void **payload, git_refdb *db, const char *refname)
 
 int git_refdb_unlock(git_refdb *db, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message)
 {
-       assert(db);
+       GIT_ASSERT_ARG(db);
 
        return db->backend->unlock(db->backend, payload, success, update_reflog, ref, sig, message);
 }
index 7e0481909db9acb45038c92deeca015812e62678..24cb22fb06f7bf92a53a4f52639d6668f804f652 100644 (file)
@@ -68,6 +68,35 @@ typedef struct refdb_fs_backend {
 
 static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
 
+GIT_INLINE(int) loose_path(
+       git_buf *out,
+       const char *base,
+       const char *refname)
+{
+       if (git_buf_joinpath(out, base, refname) < 0)
+               return -1;
+
+       return git_path_validate_filesystem_with_suffix(out->ptr, out->size,
+               CONST_STRLEN(".lock"));
+}
+
+GIT_INLINE(int) reflog_path(
+       git_buf *out,
+       git_repository *repo,
+       const char *refname)
+{
+       const char *base;
+       int error;
+
+       base = (strcmp(refname, GIT_HEAD_FILE) == 0) ? repo->gitdir :
+               repo->commondir;
+
+       if ((error = git_buf_joinpath(out, base, GIT_REFLOG_DIR)) < 0)
+               return error;
+
+       return loose_path(out, out->ptr, refname);
+}
+
 static int packref_cmp(const void *a_, const void *b_)
 {
        const struct packref *a = a_, *b = b_;
@@ -93,7 +122,7 @@ static int packed_reload(refdb_fs_backend *backend)
         */
        if (error <= 0) {
                if (error == GIT_ENOTFOUND) {
-                       git_sortedcache_clear(backend->refcache, true);
+                       GIT_UNUSED(git_sortedcache_clear(backend->refcache, true));
                        git_error_clear();
                        error = 0;
                }
@@ -102,7 +131,7 @@ static int packed_reload(refdb_fs_backend *backend)
 
        /* At this point, refresh the packed refs from the loaded buffer. */
 
-       git_sortedcache_clear(backend->refcache, false);
+       GIT_UNUSED(git_sortedcache_clear(backend->refcache, false));
 
        scan = (char *)packedrefs.ptr;
        eof  = scan + packedrefs.size;
@@ -190,7 +219,7 @@ static int packed_reload(refdb_fs_backend *backend)
 parse_failed:
        git_error_set(GIT_ERROR_REFERENCE, "corrupted packed references file");
 
-       git_sortedcache_clear(backend->refcache, false);
+       GIT_UNUSED(git_sortedcache_clear(backend->refcache, false));
        git_sortedcache_wunlock(backend->refcache);
        git_buf_dispose(&packedrefs);
 
@@ -223,9 +252,8 @@ static int loose_readbuffer(git_buf *buf, const char *base, const char *path)
 {
        int error;
 
-       /* build full path to file */
-       if ((error = git_buf_joinpath(buf, base, path)) < 0 ||
-               (error = git_futils_readbuffer(buf, buf->ptr)) < 0)
+       if ((error = loose_path(buf, base, path)) < 0 ||
+           (error = git_futils_readbuffer(buf, buf->ptr)) < 0)
                git_buf_dispose(buf);
 
        return error;
@@ -254,7 +282,8 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
        if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0)
                goto done;
 
-       git_sortedcache_wlock(backend->refcache);
+       if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
+               goto done;
 
        if (!(error = git_sortedcache_upsert(
                        (void **)&ref, backend->refcache, name))) {
@@ -331,11 +360,11 @@ static int refdb_fs_backend__exists(
        git_buf ref_path = GIT_BUF_INIT;
        int error;
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        *exists = 0;
 
-       if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
+       if ((error = loose_path(&ref_path, backend->gitpath, ref_name)) < 0)
                goto out;
 
        if (git_path_isfile(ref_path.ptr)) {
@@ -472,7 +501,7 @@ static int refdb_fs_backend__lookup(
        refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
        int error;
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        if (!(error = loose_lookup(out, backend, ref_name)))
                return 0;
@@ -549,7 +578,7 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
                }
        }
 
-       if ((error = git_buf_printf(&path, "%s/", backend->commonpath)) < 0 ||
+       if ((error = git_buf_puts(&path, backend->commonpath)) < 0 ||
                (error = git_buf_put(&path, ref_prefix, ref_prefix_len)) < 0) {
                git_buf_dispose(&path);
                return error;
@@ -678,7 +707,7 @@ static int refdb_fs_backend__iterator(
        refdb_fs_iter *iter = NULL;
        int error;
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        iter = git__calloc(1, sizeof(refdb_fs_iter));
        GIT_ERROR_CHECK_ALLOC(iter);
@@ -735,7 +764,7 @@ static bool ref_is_available(
 static int reference_path_available(
        refdb_fs_backend *backend,
        const char *new_ref,
-       const charold_ref,
+       const char *old_ref,
        int force)
 {
        size_t i;
@@ -760,7 +789,8 @@ static int reference_path_available(
                }
        }
 
-       git_sortedcache_rlock(backend->refcache);
+       if ((error = git_sortedcache_rlock(backend->refcache)) < 0)
+               return error;
 
        for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
                struct packref *ref = git_sortedcache_entry(backend->refcache, i);
@@ -783,9 +813,11 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
        git_buf ref_path = GIT_BUF_INIT;
        const char *basedir;
 
-       assert(file && backend && name);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(name);
 
-       if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
+       if (!git_path_validate(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
                git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", name);
                return GIT_EINVALIDSPEC;
        }
@@ -801,8 +833,8 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
        if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
                return error;
 
-       if (git_buf_joinpath(&ref_path, basedir, name) < 0)
-               return -1;
+       if ((error = loose_path(&ref_path, basedir, name)) < 0)
+               return error;
 
        filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS;
        if (backend->fsync)
@@ -819,7 +851,8 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
 
 static int loose_commit(git_filebuf *file, const git_reference *ref)
 {
-       assert(file && ref);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(ref);
 
        if (ref->type == GIT_REFERENCE_DIRECT) {
                char oid[GIT_OID_HEXSZ + 1];
@@ -829,7 +862,7 @@ static int loose_commit(git_filebuf *file, const git_reference *ref)
        } else if (ref->type == GIT_REFERENCE_SYMBOLIC) {
                git_filebuf_printf(file, GIT_SYMREF "%s\n", ref->target.symbolic);
        } else {
-               assert(0); /* don't let this happen */
+               GIT_ASSERT(0);
        }
 
        return git_filebuf_commit(file);
@@ -1066,7 +1099,7 @@ static int packed_write(refdb_fs_backend *backend)
 
        for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) {
                struct packref *ref = git_sortedcache_entry(refcache, i);
-               assert(ref);
+               GIT_ASSERT(ref);
 
                if ((error = packed_find_peel(backend, ref)) < 0)
                        goto fail;
@@ -1140,8 +1173,11 @@ static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name,
        if (!old_id && !old_target)
                return 0;
 
-       if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0)
+       if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0) {
+               if (error == GIT_ENOTFOUND && old_id && git_oid_is_zero(old_id))
+                       return 0;
                goto out;
+       }
 
        /* If the types don't match, there's no way the values do */
        if (old_id && old_ref->type != GIT_REFERENCE_DIRECT) {
@@ -1219,7 +1255,7 @@ static int refdb_fs_backend__write(
        git_filebuf file = GIT_FILEBUF_INIT;
        int error = 0;
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
                return error;
@@ -1292,7 +1328,7 @@ on_error:
         return error;
 }
 
-static void refdb_fs_backend__prune_refs(
+static int refdb_fs_backend__prune_refs(
        refdb_fs_backend *backend,
        const char *ref_name,
        const char *prefix)
@@ -1300,10 +1336,12 @@ static void refdb_fs_backend__prune_refs(
        git_buf relative_path = GIT_BUF_INIT;
        git_buf base_path = GIT_BUF_INIT;
        size_t commonlen;
+       int error;
 
-       assert(backend && ref_name);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(ref_name);
 
-       if (git_buf_sets(&relative_path, ref_name) < 0)
+       if ((error = git_buf_sets(&relative_path, ref_name)) < 0)
                goto cleanup;
 
        git_path_squash_slashes(&relative_path);
@@ -1313,20 +1351,33 @@ static void refdb_fs_backend__prune_refs(
 
                git_buf_truncate(&relative_path, commonlen);
 
-               if (prefix) {
-                       if (git_buf_join3(&base_path, '/', backend->commonpath, prefix, git_buf_cstr(&relative_path)) < 0)
-                               goto cleanup;
-               } else {
-                       if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
-                               goto cleanup;
-               }
+               if (prefix)
+                       error = git_buf_join3(&base_path, '/',
+                               backend->commonpath, prefix,
+                               git_buf_cstr(&relative_path));
+               else
+                       error = git_buf_joinpath(&base_path,
+                               backend->commonpath,
+                               git_buf_cstr(&relative_path));
+
+               if (!error)
+                       error = git_path_validate_filesystem(base_path.ptr, base_path.size);
+
+               if (error < 0)
+                       goto cleanup;
+
+               error = git_futils_rmdir_r(ref_name + commonlen,
+                       git_buf_cstr(&base_path),
+                       GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
 
-               git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
+               if (error == GIT_ENOTFOUND)
+                       error = 0;
        }
 
 cleanup:
        git_buf_dispose(&relative_path);
        git_buf_dispose(&base_path);
+       return error;
 }
 
 static int refdb_fs_backend__delete(
@@ -1338,7 +1389,8 @@ static int refdb_fs_backend__delete(
        git_filebuf file = GIT_FILEBUF_INIT;
        int error = 0;
 
-       assert(backend && ref_name);
+       GIT_ASSERT_ARG(backend);
+       GIT_ASSERT_ARG(ref_name);
 
        if ((error = loose_lock(&file, backend, ref_name)) < 0)
                return error;
@@ -1353,19 +1405,19 @@ static int refdb_fs_backend__delete(
 
 static int loose_delete(refdb_fs_backend *backend, const char *ref_name)
 {
-       git_buf loose_path = GIT_BUF_INIT;
+       git_buf path = GIT_BUF_INIT;
        int error = 0;
 
-       if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0)
-               return -1;
+       if ((error = loose_path(&path, backend->commonpath, ref_name)) < 0)
+               return error;
 
-       error = p_unlink(loose_path.ptr);
+       error = p_unlink(path.ptr);
        if (error < 0 && errno == ENOENT)
                error = GIT_ENOTFOUND;
        else if (error != 0)
                error = -1;
 
-       git_buf_dispose(&loose_path);
+       git_buf_dispose(&path);
 
        return error;
 }
@@ -1424,7 +1476,7 @@ static int refdb_fs_backend__delete_tail(
 cleanup:
        git_filebuf_cleanup(file);
        if (error == 0)
-               refdb_fs_backend__prune_refs(backend, ref_name, "");
+               error = refdb_fs_backend__prune_refs(backend, ref_name, "");
        return error;
 }
 
@@ -1444,7 +1496,7 @@ static int refdb_fs_backend__rename(
        git_filebuf file = GIT_FILEBUF_INIT;
        int error;
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        if ((error = reference_path_available(
                        backend, new_name, old_name, force)) < 0 ||
@@ -1497,7 +1549,7 @@ static int refdb_fs_backend__compress(git_refdb_backend *_backend)
        int error;
        refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
 
-       assert(backend);
+       GIT_ASSERT_ARG(backend);
 
        if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */
            (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */
@@ -1511,7 +1563,8 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend)
 {
        refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
 
-       assert(backend);
+       if (!backend)
+               return;
 
        git_sortedcache_free(backend->refcache);
        git__free(backend->gitpath);
@@ -1556,8 +1609,9 @@ static char *setup_namespace(git_repository *repo, const char *in)
                        GIT_MKDIR_PATH, NULL) < 0)
                goto done;
 
-       /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
+       /* Return root of the namespaced gitpath, i.e. without the trailing 'refs' */
        git_buf_rtruncate_at_char(&path, '/');
+       git_buf_putc(&path, '/');
        out = git_buf_detach(&path);
 
 done:
@@ -1658,13 +1712,6 @@ static int create_new_reflog_file(const char *filepath)
        return p_close(fd);
 }
 
-GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
-{
-       if (strcmp(name, GIT_HEAD_FILE) == 0)
-               return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name);
-       return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name);
-}
-
 static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
 {
        refdb_fs_backend *backend;
@@ -1672,12 +1719,12 @@ static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *
        git_buf path = GIT_BUF_INIT;
        int error;
 
-       assert(_backend && name);
+       GIT_ASSERT_ARG(_backend && name);
 
        backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
        repo = backend->repo;
 
-       if ((error = retrieve_reflog_path(&path, repo, name)) < 0)
+       if ((error = reflog_path(&path, repo, name)) < 0)
                return error;
 
        error = create_new_reflog_file(git_buf_cstr(&path));
@@ -1691,7 +1738,7 @@ static int has_reflog(git_repository *repo, const char *name)
        int ret = 0;
        git_buf path = GIT_BUF_INIT;
 
-       if (retrieve_reflog_path(&path, repo, name) < 0)
+       if (reflog_path(&path, repo, name) < 0)
                goto cleanup;
 
        ret = git_path_isfile(git_buf_cstr(&path));
@@ -1705,7 +1752,8 @@ static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *nam
 {
        refdb_fs_backend *backend;
 
-       assert(_backend && name);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(name);
 
        backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
 
@@ -1721,7 +1769,9 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend,
        git_repository *repo;
        refdb_fs_backend *backend;
 
-       assert(out && _backend && name);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(name);
 
        backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
        repo = backend->repo;
@@ -1729,7 +1779,7 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend,
        if (reflog_alloc(&log, name) < 0)
                return -1;
 
-       if (retrieve_reflog_path(&log_path, repo, name) < 0)
+       if (reflog_path(&log_path, repo, name) < 0)
                goto cleanup;
 
        error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path));
@@ -1806,12 +1856,12 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
 
        repo = backend->repo;
 
-       if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
+       if (!git_path_validate(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
                git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", refname);
                return GIT_EINVALIDSPEC;
        }
 
-       if (retrieve_reflog_path(&log_path, repo, refname) < 0)
+       if (reflog_path(&log_path, repo, refname) < 0)
                return -1;
 
        if (!git_path_isfile(git_buf_cstr(&log_path))) {
@@ -1838,7 +1888,8 @@ static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflo
        git_buf log = GIT_BUF_INIT;
        git_filebuf fbuf = GIT_FILEBUF_INIT;
 
-       assert(_backend && reflog);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(reflog);
 
        backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
 
@@ -1911,7 +1962,7 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
        if ((error = serialize_reflog_entry(&buf, &old_id, &new_id, who, message)) < 0)
                goto cleanup;
 
-       if ((error = retrieve_reflog_path(&path, repo, ref->name)) < 0)
+       if ((error = reflog_path(&path, repo, ref->name)) < 0)
                goto cleanup;
 
        if (((error = git_futils_mkpath2file(git_buf_cstr(&path), 0777)) < 0) &&
@@ -1960,7 +2011,9 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
        git_repository *repo;
        refdb_fs_backend *backend;
 
-       assert(_backend && old_name && new_name);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(old_name);
+       GIT_ASSERT_ARG(new_name);
 
        backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
        repo = backend->repo;
@@ -1972,11 +2025,11 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
        if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0)
                return -1;
 
-       if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0)
-               return -1;
+       if ((error = loose_path(&old_path, git_buf_cstr(&temp_path), old_name)) < 0)
+               return error;
 
-       if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0)
-               return -1;
+       if ((error = loose_path(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized))) < 0)
+               return error;
 
        if (!git_path_exists(git_buf_cstr(&old_path))) {
                error = GIT_ENOTFOUND;
@@ -1990,8 +2043,8 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
         *  - a/b -> a/b/c
         *  - a/b/c/d -> a/b/c
         */
-       if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0)
-               return -1;
+       if ((error = loose_path(&temp_path, git_buf_cstr(&temp_path), "temp_reflog")) < 0)
+               return error;
 
        if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path), GIT_REFLOG_FILE_MODE)) < 0) {
                error = -1;
@@ -2037,9 +2090,10 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name
        git_buf path = GIT_BUF_INIT;
        int error;
 
-       assert(_backend && name);
+       GIT_ASSERT_ARG(_backend);
+       GIT_ASSERT_ARG(name);
 
-       if ((error = retrieve_reflog_path(&path, backend->repo, name)) < 0)
+       if ((error = reflog_path(&path, backend->repo, name)) < 0)
                goto out;
 
        if (!git_path_exists(path.ptr))
@@ -2048,7 +2102,7 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name
        if ((error = p_unlink(path.ptr)) < 0)
                goto out;
 
-       refdb_fs_backend__prune_refs(backend, name, GIT_REFLOG_DIR);
+       error = refdb_fs_backend__prune_refs(backend, name, GIT_REFLOG_DIR);
 
 out:
        git_buf_dispose(&path);
index 34537aa1f83b6315c27136ca753284edc5bfc70f..1e9c0d4f12be37aa42684e562fbf5f44cc09247a 100644 (file)
@@ -50,7 +50,9 @@ int git_reflog_read(git_reflog **reflog, git_repository *repo,  const char *name
        git_refdb *refdb;
        int error;
 
-       assert(reflog && repo && name);
+       GIT_ASSERT_ARG(reflog);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
                return error;
@@ -62,7 +64,8 @@ int git_reflog_write(git_reflog *reflog)
 {
        git_refdb *db;
 
-       assert(reflog && reflog->db);
+       GIT_ASSERT_ARG(reflog);
+       GIT_ASSERT_ARG(reflog->db);
 
        db = reflog->db;
        return db->backend->reflog_write(db->backend, reflog);
@@ -73,7 +76,9 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign
        const git_reflog_entry *previous;
        git_reflog_entry *entry;
 
-       assert(reflog && new_oid && committer);
+       GIT_ASSERT_ARG(reflog);
+       GIT_ASSERT_ARG(new_oid);
+       GIT_ASSERT_ARG(committer);
 
        entry = git__calloc(1, sizeof(git_reflog_entry));
        GIT_ERROR_CHECK_ALLOC(entry);
@@ -139,13 +144,13 @@ int git_reflog_delete(git_repository *repo, const char *name)
 
 size_t git_reflog_entrycount(git_reflog *reflog)
 {
-       assert(reflog);
+       GIT_ASSERT_ARG_WITH_RETVAL(reflog, 0);
        return reflog->entries.length;
 }
 
-const git_reflog_entry * git_reflog_entry_byindex(const git_reflog *reflog, size_t idx)
+const git_reflog_entry *git_reflog_entry_byindex(const git_reflog *reflog, size_t idx)
 {
-       assert(reflog);
+       GIT_ASSERT_ARG_WITH_RETVAL(reflog, NULL);
 
        if (idx >= reflog->entries.length)
                return NULL;
@@ -154,27 +159,27 @@ const git_reflog_entry * git_reflog_entry_byindex(const git_reflog *reflog, size
                &reflog->entries, reflog_inverse_index(idx, reflog->entries.length));
 }
 
-const git_oid * git_reflog_entry_id_old(const git_reflog_entry *entry)
+const git_oid *git_reflog_entry_id_old(const git_reflog_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return &entry->oid_old;
 }
 
-const git_oid * git_reflog_entry_id_new(const git_reflog_entry *entry)
+const git_oid *git_reflog_entry_id_new(const git_reflog_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return &entry->oid_cur;
 }
 
-const git_signature * git_reflog_entry_committer(const git_reflog_entry *entry)
+const git_signature *git_reflog_entry_committer(const git_reflog_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return entry->committer;
 }
 
-const char * git_reflog_entry_message(const git_reflog_entry *entry)
+const char *git_reflog_entry_message(const git_reflog_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return entry->msg;
 }
 
index 51635a9e4cdc44e29657b122b3947afaa16e4d72..8acfa84a5a66ba116bc6b20138015eda89748aed 100644 (file)
@@ -50,7 +50,8 @@ git_reference *git_reference__alloc_symbolic(
 {
        git_reference *ref;
 
-       assert(name && target);
+       GIT_ASSERT_ARG_WITH_RETVAL(name, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(target, NULL);
 
        ref = alloc_ref(name);
        if (!ref)
@@ -73,7 +74,8 @@ git_reference *git_reference__alloc(
 {
        git_reference *ref;
 
-       assert(name && oid);
+       GIT_ASSERT_ARG_WITH_RETVAL(name, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(oid, NULL);
 
        ref = alloc_ref(name);
        if (!ref)
@@ -94,7 +96,8 @@ git_reference *git_reference__realloc(
        size_t namelen, reflen;
        git_reference *rewrite = NULL;
 
-       assert(ptr_to_ref && name);
+       GIT_ASSERT_ARG_WITH_RETVAL(ptr_to_ref, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(name, NULL);
 
        namelen = strlen(name);
 
@@ -215,7 +218,9 @@ int git_reference_lookup_resolved(
        git_refdb *refdb;
        int error = 0;
 
-       assert(ref_out && repo && name);
+       GIT_ASSERT_ARG(ref_out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 ||
            (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 ||
@@ -239,12 +244,12 @@ int git_reference_lookup_resolved(
 
 int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
 {
-       int error = 0, i;
+       int error = 0, i, valid;
        bool fallbackmode = true, foundvalid = false;
        git_reference *ref;
        git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT;
 
-       static const charformatters[] = {
+       static const char *formatters[] = {
                "%s",
                GIT_REFS_DIR "%s",
                GIT_REFS_TAGS_DIR "%s",
@@ -265,10 +270,11 @@ int git_reference_dwim(git_reference **out, git_repository *repo, const char *re
 
                git_buf_clear(&refnamebuf);
 
-               if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0)
+               if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0 ||
+                   (error = git_reference_name_is_valid(&valid, git_buf_cstr(&refnamebuf))) < 0)
                        goto cleanup;
 
-               if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) {
+               if (!valid) {
                        error = GIT_EINVALIDSPEC;
                        continue;
                }
@@ -306,25 +312,25 @@ cleanup:
  */
 git_reference_t git_reference_type(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
        return ref->type;
 }
 
 const char *git_reference_name(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL);
        return ref->name;
 }
 
 git_repository *git_reference_owner(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL);
        return ref->db->repo;
 }
 
 const git_oid *git_reference_target(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL);
 
        if (ref->type != GIT_REFERENCE_DIRECT)
                return NULL;
@@ -334,7 +340,7 @@ const git_oid *git_reference_target(const git_reference *ref)
 
 const git_oid *git_reference_target_peel(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL);
 
        if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel))
                return NULL;
@@ -344,7 +350,7 @@ const git_oid *git_reference_target_peel(const git_reference *ref)
 
 const char *git_reference_symbolic_target(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL);
 
        if (ref->type != GIT_REFERENCE_SYMBOLIC)
                return NULL;
@@ -369,8 +375,9 @@ static int reference__create(
        git_reference *ref = NULL;
        int error = 0;
 
-       assert(repo && name);
-       assert(symbolic || signature);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(symbolic || signature);
 
        if (ref_out)
                *ref_out = NULL;
@@ -384,7 +391,7 @@ static int reference__create(
                return error;
 
        if (oid != NULL) {
-               assert(symbolic == NULL);
+               GIT_ASSERT(symbolic == NULL);
 
                if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) {
                        git_error_set(GIT_ERROR_REFERENCE,
@@ -456,7 +463,7 @@ int git_reference_create_matching(
        int error;
        git_signature *who = NULL;
 
-       assert(id);
+       GIT_ASSERT_ARG(id);
 
        if ((error = git_reference__log_signature(&who, repo)) < 0)
                return error;
@@ -491,7 +498,7 @@ int git_reference_symbolic_create_matching(
        int error;
        git_signature *who = NULL;
 
-       assert(target);
+       GIT_ASSERT_ARG(target);
 
        if ((error = git_reference__log_signature(&who, repo)) < 0)
                return error;
@@ -532,7 +539,9 @@ int git_reference_set_target(
        int error;
        git_repository *repo;
 
-       assert(out && ref && id);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ref);
+       GIT_ASSERT_ARG(id);
 
        repo = ref->db->repo;
 
@@ -559,7 +568,9 @@ int git_reference_symbolic_set_target(
 {
        int error;
 
-       assert(out && ref && target);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ref);
+       GIT_ASSERT_ARG(target);
 
        if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
                return error;
@@ -610,7 +621,8 @@ int git_reference_rename(
        git_repository *repo;
        int error;
 
-       assert(out && ref);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(ref);
 
        repo = git_reference_owner(ref);
 
@@ -776,7 +788,8 @@ int git_reference_list(
 {
        git_vector ref_list;
 
-       assert(array && repo);
+       GIT_ASSERT_ARG(array);
+       GIT_ASSERT_ARG(repo);
 
        array->strings = NULL;
        array->count = 0;
@@ -860,7 +873,8 @@ static bool is_all_caps_and_underscore(const char *name, size_t len)
        size_t i;
        char c;
 
-       assert(name && len > 0);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(len > 0);
 
        for (i = 0; i < len; i++)
        {
@@ -891,7 +905,7 @@ int git_reference__normalize_name(
        git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
 #endif
 
-       assert(name);
+       GIT_ASSERT_ARG(name);
 
        process_flags = flags;
        current = (char *)name;
@@ -1023,7 +1037,8 @@ int git_reference_normalize_name(
                goto cleanup;
        }
 
-       git_buf_copy_cstr(buffer_out, buffer_size, &buf);
+       if ((error = git_buf_copy_cstr(buffer_out, buffer_size, &buf)) < 0)
+               goto cleanup;
 
        error = 0;
 
@@ -1039,7 +1054,9 @@ int git_reference_cmp(
        const git_reference *ref2)
 {
        git_reference_t type1, type2;
-       assert(ref1 && ref2);
+
+       GIT_ASSERT_ARG(ref1);
+       GIT_ASSERT_ARG(ref2);
 
        type1 = git_reference_type(ref1);
        type2 = git_reference_type(ref2);
@@ -1162,7 +1179,8 @@ int git_reference_has_log(git_repository *repo, const char *refname)
        int error;
        git_refdb *refdb;
 
-       assert(repo && refname);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(refname);
 
        if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
                return error;
@@ -1175,7 +1193,8 @@ int git_reference_ensure_log(git_repository *repo, const char *refname)
        int error;
        git_refdb *refdb;
 
-       assert(repo && refname);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(refname);
 
        if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
                return error;
@@ -1190,7 +1209,7 @@ int git_reference__is_branch(const char *ref_name)
 
 int git_reference_is_branch(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
        return git_reference__is_branch(ref->name);
 }
 
@@ -1201,7 +1220,7 @@ int git_reference__is_remote(const char *ref_name)
 
 int git_reference_is_remote(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
        return git_reference__is_remote(ref->name);
 }
 
@@ -1212,7 +1231,7 @@ int git_reference__is_tag(const char *ref_name)
 
 int git_reference_is_tag(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
        return git_reference__is_tag(ref->name);
 }
 
@@ -1223,11 +1242,11 @@ int git_reference__is_note(const char *ref_name)
 
 int git_reference_is_note(const git_reference *ref)
 {
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
        return git_reference__is_note(ref->name);
 }
 
-static int peel_error(int error, const git_reference *ref, const charmsg)
+static int peel_error(int error, const git_reference *ref, const char *msg)
 {
        git_error_set(
                GIT_ERROR_INVALID,
@@ -1245,7 +1264,7 @@ int git_reference_peel(
        git_object *target = NULL;
        int error;
 
-       assert(ref);
+       GIT_ASSERT_ARG(ref);
 
        if (ref->type == GIT_REFERENCE_DIRECT) {
                resolved = ref;
@@ -1287,19 +1306,30 @@ cleanup:
        return error;
 }
 
-int git_reference__is_valid_name(const char *refname, unsigned int flags)
+int git_reference__name_is_valid(
+       int *valid,
+       const char *refname,
+       unsigned int flags)
 {
-       if (git_reference__normalize_name(NULL, refname, flags) < 0) {
-               git_error_clear();
-               return false;
-       }
+       int error;
 
-       return true;
+       GIT_ASSERT(valid && refname);
+
+       *valid = 0;
+
+       error = git_reference__normalize_name(NULL, refname, flags);
+
+       if (!error)
+               *valid = 1;
+       else if (error == GIT_EINVALIDSPEC)
+               error = 0;
+
+       return error;
 }
 
-int git_reference_is_valid_name(const char *refname)
+int git_reference_name_is_valid(int *valid, const char *refname)
 {
-       return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
+       return git_reference__name_is_valid(valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
 }
 
 const char *git_reference__shorthand(const char *name)
@@ -1313,7 +1343,7 @@ const char *git_reference__shorthand(const char *name)
        else if (!git__prefixcmp(name, GIT_REFS_DIR))
                return name + strlen(GIT_REFS_DIR);
 
-       /* No shorthands are avaiable, so just return the name */
+       /* No shorthands are available, so just return the name. */
        return name;
 }
 
@@ -1326,7 +1356,10 @@ int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_re
 {
        int error;
        git_reference *tmp_ref;
-       assert(unborn && ref && repo);
+
+       GIT_ASSERT_ARG(unborn);
+       GIT_ASSERT_ARG(ref);
+       GIT_ASSERT_ARG(repo);
 
        if (ref->type == GIT_REFERENCE_DIRECT) {
                *unborn = 0;
@@ -1345,3 +1378,18 @@ int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_re
 
        return 0;
 }
+
+/* Deprecated functions */
+
+#ifndef GIT_DEPRECATE_HARD
+
+int git_reference_is_valid_name(const char *refname)
+{
+       int valid = 0;
+
+       git_reference__name_is_valid(&valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
+
+       return valid;
+}
+
+#endif
index e0ee03b0e2aa8f47763b2be5c4bba1fba365b8d1..376a512f85dfcfb71d670bf57fb597a8a8b0ad50 100644 (file)
@@ -85,7 +85,7 @@ git_reference *git_reference__realloc(git_reference **ptr_to_ref, const char *na
 
 int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags);
 int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid, const git_signature *sig, const char *log_message);
-int git_reference__is_valid_name(const char *refname, unsigned int flags);
+int git_reference__name_is_valid(int *valid, const char *name, unsigned int flags);
 int git_reference__is_branch(const char *ref_name);
 int git_reference__is_remote(const char *ref_name);
 int git_reference__is_tag(const char *ref_name);
index 854240a846045402c39544195a83405edfcf6b84..c72721a437300f64709e102a374730ba407ddf9f 100644 (file)
@@ -21,9 +21,11 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
        size_t llen;
        int is_glob = 0;
        const char *lhs, *rhs;
-       int flags;
+       int valid = 0;
+       unsigned int flags;
 
-       assert(refspec && input);
+       GIT_ASSERT_ARG(refspec);
+       GIT_ASSERT_ARG(input);
 
        memset(refspec, 0x0, sizeof(git_refspec));
        refspec->push = !is_fetch;
@@ -75,57 +77,69 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
 
        if (is_fetch) {
                /*
-                       * LHS
-                       * - empty is allowed; it means HEAD.
-                       * - otherwise it must be a valid looking ref.
-                       */
+                * LHS
+                * - empty is allowed; it means HEAD.
+                * - otherwise it must be a valid looking ref.
+                */
                if (!*refspec->src)
                        ; /* empty is ok */
-               else if (!git_reference__is_valid_name(refspec->src, flags))
+               else if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
+                       goto on_error;
+               else if (!valid)
                        goto invalid;
+
                /*
-                       * RHS
-                       * - missing is ok, and is same as empty.
-                       * - empty is ok; it means not to store.
-                       * - otherwise it must be a valid looking ref.
-                       */
+                * RHS
+                * - missing is ok, and is same as empty.
+                * - empty is ok; it means not to store.
+                * - otherwise it must be a valid looking ref.
+                */
                if (!refspec->dst)
                        ; /* ok */
                else if (!*refspec->dst)
                        ; /* ok */
-               else if (!git_reference__is_valid_name(refspec->dst, flags))
+               else if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
+                       goto on_error;
+               else if (!valid)
                        goto invalid;
        } else {
                /*
-                       * LHS
-                       * - empty is allowed; it means delete.
-                       * - when wildcarded, it must be a valid looking ref.
-                       * - otherwise, it must be an extended SHA-1, but
-                       *   there is no existing way to validate this.
-                       */
+                * LHS
+                * - empty is allowed; it means delete.
+                * - when wildcarded, it must be a valid looking ref.
+                * - otherwise, it must be an extended SHA-1, but
+                *   there is no existing way to validate this.
+                */
                if (!*refspec->src)
                        ; /* empty is ok */
                else if (is_glob) {
-                       if (!git_reference__is_valid_name(refspec->src, flags))
+                       if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
+                               goto on_error;
+                       else if (!valid)
                                goto invalid;
                }
                else {
                        ; /* anything goes, for now */
                }
+
                /*
-                       * RHS
-                       * - missing is allowed, but LHS then must be a
-                       *   valid looking ref.
-                       * - empty is not allowed.
-                       * - otherwise it must be a valid looking ref.
-                       */
+                * RHS
+                * - missing is allowed, but LHS then must be a
+                *   valid looking ref.
+                * - empty is not allowed.
+                * - otherwise it must be a valid looking ref.
+                */
                if (!refspec->dst) {
-                       if (!git_reference__is_valid_name(refspec->src, flags))
+                       if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
+                               goto on_error;
+                       else if (!valid)
                                goto invalid;
                } else if (!*refspec->dst) {
                        goto invalid;
                } else {
-                       if (!git_reference__is_valid_name(refspec->dst, flags))
+                       if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
+                               goto on_error;
+                       else if (!valid)
                                goto invalid;
                }
 
@@ -141,11 +155,14 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
 
        return 0;
 
- invalid:
-        git_error_set(
-                GIT_ERROR_INVALID,
-                "'%s' is not a valid refspec.", input);
-        git_refspec__dispose(refspec);
+invalid:
+       git_error_set(GIT_ERROR_INVALID,
+                     "'%s' is not a valid refspec.", input);
+       git_refspec__dispose(refspec);
+       return GIT_EINVALIDSPEC;
+
+on_error:
+       git_refspec__dispose(refspec);
        return -1;
 }
 
@@ -164,7 +181,8 @@ void git_refspec__dispose(git_refspec *refspec)
 int git_refspec_parse(git_refspec **out_refspec, const char *input, int is_fetch)
 {
        git_refspec *refspec;
-       assert(out_refspec && input);
+       GIT_ASSERT_ARG(out_refspec);
+       GIT_ASSERT_ARG(input);
 
        *out_refspec = NULL;
 
@@ -203,7 +221,7 @@ const char *git_refspec_string(const git_refspec *refspec)
 
 int git_refspec_force(const git_refspec *refspec)
 {
-       assert(refspec);
+       GIT_ASSERT_ARG(refspec);
 
        return refspec->force;
 }
@@ -229,8 +247,11 @@ static int refspec_transform(
 {
        const char *from_star, *to_star;
        size_t replacement_len, star_offset;
+       int error;
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
-       git_buf_sanitize(out);
        git_buf_clear(out);
 
        /*
@@ -242,7 +263,7 @@ static int refspec_transform(
        from_star = strchr(from, '*');
        to_star = strchr(to, '*');
 
-       assert(from_star && to_star);
+       GIT_ASSERT(from_star && to_star);
 
        /* star offset, both in 'from' and in 'name' */
        star_offset = from_star - from;
@@ -262,8 +283,14 @@ static int refspec_transform(
 
 int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name)
 {
-       assert(out && spec && name);
-       git_buf_sanitize(out);
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(name);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        if (!git_refspec_src_matches(spec, name)) {
                git_error_set(GIT_ERROR_INVALID, "ref '%s' doesn't match the source", name);
@@ -278,8 +305,14 @@ int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *nam
 
 int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name)
 {
-       assert(out && spec && name);
-       git_buf_sanitize(out);
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(name);
+
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        if (!git_refspec_dst_matches(spec, name)) {
                git_error_set(GIT_ERROR_INVALID, "ref '%s' doesn't match the destination", name);
@@ -306,14 +339,15 @@ int git_refspec__serialize(git_buf *out, const git_refspec *refspec)
 
 int git_refspec_is_wildcard(const git_refspec *spec)
 {
-       assert(spec && spec->src);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(spec->src);
 
        return (spec->src[strlen(spec->src) - 1] == '*');
 }
 
 git_direction git_refspec_direction(const git_refspec *spec)
 {
-       assert(spec);
+       GIT_ASSERT_ARG(spec);
 
        return spec->push;
 }
@@ -325,14 +359,16 @@ int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs)
        git_remote_head key;
        git_refspec *cur;
 
-       const charformatters[] = {
+       const char *formatters[] = {
                GIT_REFS_DIR "%s",
                GIT_REFS_TAGS_DIR "%s",
                GIT_REFS_HEADS_DIR "%s",
                NULL
        };
 
-       assert(out && spec && refs);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(refs);
 
        cur = git__calloc(1, sizeof(git_refspec));
        GIT_ERROR_CHECK_ALLOC(cur);
index 51e99dc949be0c0039e4c1c109a6820fa5cc7ab7..56d7e42db0b5272f0c5fe766a4158be8e092cd4b 100644 (file)
@@ -82,9 +82,11 @@ static int download_tags_value(git_remote *remote, git_config *cfg)
 
 static int ensure_remote_name_is_valid(const char *name)
 {
-       int error = 0;
+       int valid, error;
+
+       error = git_remote_name_is_valid(&valid, name);
 
-       if (!git_remote_is_valid_name(name)) {
+       if (!error && !valid) {
                git_error_set(
                        GIT_ERROR_CONFIG,
                        "'%s' is not a valid remote name.", name ? name : "(null)");
@@ -110,12 +112,8 @@ static int write_add_refspec(git_repository *repo, const char *name, const char
        if ((error = ensure_remote_name_is_valid(name)) < 0)
                return error;
 
-       if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
-               if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
-                       error = GIT_EINVALIDSPEC;
-
+       if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0)
                return error;
-       }
 
        git_refspec__dispose(&spec);
 
@@ -123,7 +121,7 @@ static int write_add_refspec(git_repository *repo, const char *name, const char
                return error;
 
        /*
-        * "$^" is a unmatcheable regexp: it will not match anything at all, so
+        * "$^" is an unmatchable regexp: it will not match anything at all, so
         * all values will be considered new and we will not replace any
         * present value.
         */
@@ -212,7 +210,8 @@ int git_remote_create_with_opts(git_remote **out, const char *url, const git_rem
        const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
        int error = -1;
 
-       assert(out && url);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(url);
 
        if (!opts) {
                opts = &dummy_opts;
@@ -461,7 +460,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
        struct refspec_cb_data data = { NULL };
        bool optional_setting_found = false, found;
 
-       assert(out && repo && name);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = ensure_remote_name_is_valid(name)) < 0)
                return error;
@@ -583,29 +584,46 @@ static int lookup_remote_prune_config(git_remote *remote, git_config *config, co
 
 const char *git_remote_name(const git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG_WITH_RETVAL(remote, NULL);
        return remote->name;
 }
 
 git_repository *git_remote_owner(const git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG_WITH_RETVAL(remote, NULL);
        return remote->repo;
 }
 
 const char *git_remote_url(const git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG_WITH_RETVAL(remote, NULL);
        return remote->url;
 }
 
+int git_remote_set_instance_url(git_remote *remote, const char *url)
+{
+       char *tmp;
+
+       GIT_ASSERT_ARG(remote);
+       GIT_ASSERT_ARG(url);
+
+       if ((tmp = git__strdup(url)) == NULL)
+               return -1;
+
+       git__free(remote->url);
+       remote->url = tmp;
+
+       return 0;
+}
+
 static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
 {
        git_config *cfg;
        git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
        int error;
 
-       assert(repo && remote);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(remote);
 
        if ((error = ensure_remote_name_is_valid(remote)) < 0)
                return error;
@@ -639,44 +657,84 @@ int git_remote_set_url(git_repository *repo, const char *remote, const char *url
 
 const char *git_remote_pushurl(const git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG_WITH_RETVAL(remote, NULL);
        return remote->pushurl;
 }
 
-int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
+int git_remote_set_instance_pushurl(git_remote *remote, const char *url)
+{
+       char *tmp;
+
+       GIT_ASSERT_ARG(remote);
+       GIT_ASSERT_ARG(url);
+
+       if ((tmp = git__strdup(url)) == NULL)
+               return -1;
+
+       git__free(remote->pushurl);
+       remote->pushurl = tmp;
+
+       return 0;
+}
+
+int git_remote_set_pushurl(git_repository *repo, const char *remote, const char *url)
 {
        return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
 }
 
-static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
+static int resolve_url(
+       git_buf *resolved_url,
+       const char *url,
+       int direction,
+       const git_remote_callbacks *callbacks)
 {
-       int status;
+#ifdef GIT_DEPRECATE_HARD
+       GIT_UNUSED(direction);
+       GIT_UNUSED(callbacks);
+#else
+       int status, error;
 
        if (callbacks && callbacks->resolve_url) {
                git_buf_clear(resolved_url);
                status = callbacks->resolve_url(resolved_url, url, direction, callbacks->payload);
                if (status != GIT_PASSTHROUGH) {
                        git_error_set_after_callback_function(status, "git_resolve_url_cb");
-                       git_buf_sanitize(resolved_url);
+
+                       if ((error = git_buf_sanitize(resolved_url)) < 0)
+                               return error;
+
                        return status;
                }
        }
+#endif
 
        return git_buf_sets(resolved_url, url);
 }
 
-int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks)
+int git_remote__urlfordirection(
+       git_buf *url_out,
+       struct git_remote *remote,
+       int direction,
+       const git_remote_callbacks *callbacks)
 {
        const char *url = NULL;
 
-       assert(remote);
-       assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
+       GIT_ASSERT_ARG(remote);
+       GIT_ASSERT_ARG(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
 
-       if (direction == GIT_DIRECTION_FETCH) {
+       if (callbacks && callbacks->remote_ready) {
+               int status = callbacks->remote_ready(remote, direction, callbacks->payload);
+
+               if (status != 0 && status != GIT_PASSTHROUGH) {
+                       git_error_set_after_callback_function(status, "git_remote_ready_cb");
+                       return status;
+               }
+       }
+
+       if (direction == GIT_DIRECTION_FETCH)
                url = remote->url;
-       } else if (direction == GIT_DIRECTION_PUSH) {
+       else if (direction == GIT_DIRECTION_PUSH)
                url = remote->pushurl ? remote->pushurl : remote->url;
-       }
 
        if (!url) {
                git_error_set(GIT_ERROR_INVALID,
@@ -685,6 +743,7 @@ int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int
                        direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
                return GIT_EINVALID;
        }
+
        return resolve_url(url_out, url, direction, callbacks);
 }
 
@@ -715,7 +774,7 @@ int git_remote__connect(git_remote *remote, git_direction direction, const git_r
        git_credential_acquire_cb credentials = NULL;
        git_transport_cb transport = NULL;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (callbacks) {
                GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
@@ -780,7 +839,7 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re
 
 int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (!remote->transport) {
                git_error_set(GIT_ERROR_NET, "this remote has never connected");
@@ -790,75 +849,147 @@ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote
        return remote->transport->ls(out, size, remote->transport);
 }
 
-int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
+static int lookup_config(char **out, git_config *cfg, const char *name)
 {
-       git_config *cfg;
        git_config_entry *ce = NULL;
-       git_buf val = GIT_BUF_INIT;
        int error;
 
-       assert(remote);
+       if ((error = git_config__lookup_entry(&ce, cfg, name, false)) < 0)
+               return error;
+
+       if (ce && ce->value) {
+               *out = git__strdup(ce->value);
+               GIT_ERROR_CHECK_ALLOC(*out);
+       } else {
+               error = GIT_ENOTFOUND;
+       }
 
-       if (!proxy_url || !remote->repo)
-               return -1;
+       git_config_entry_free(ce);
+       return error;
+}
 
-       *proxy_url = NULL;
+static void url_config_trim(git_net_url *url)
+{
+       size_t len = strlen(url->path);
 
-       if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
-               return error;
+       if (url->path[len - 1] == '/') {
+               len--;
+       } else {
+               while (len && url->path[len - 1] != '/')
+                       len--;
+       }
 
-       /* Go through the possible sources for proxy configuration, from most specific
-        * to least specific. */
+       url->path[len] = '\0';
+}
+
+static int http_proxy_config(char **out, git_remote *remote, git_net_url *url)
+{
+       git_config *cfg = NULL;
+       git_buf buf = GIT_BUF_INIT;
+       git_net_url lookup_url = GIT_NET_URL_INIT;
+       int error;
+
+       if ((error = git_net_url_dup(&lookup_url, url)) < 0)
+               goto done;
+
+       if (remote->repo) {
+               if ((error = git_repository_config(&cfg, remote->repo)) < 0)
+                       goto done;
+       } else {
+               if ((error = git_config_open_default(&cfg)) < 0)
+                       goto done;
+       }
 
        /* remote.<name>.proxy config setting */
        if (remote->name && remote->name[0]) {
-               git_buf buf = GIT_BUF_INIT;
+               git_buf_clear(&buf);
 
-               if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
-                       return error;
+               if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0 ||
+                   (error = lookup_config(out, cfg, buf.ptr)) != GIT_ENOTFOUND)
+                       goto done;
+       }
 
-               error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
-               git_buf_dispose(&buf);
+       while (true) {
+               git_buf_clear(&buf);
 
-               if (error < 0)
-                       return error;
+               if ((error = git_buf_puts(&buf, "http.")) < 0 ||
+                   (error = git_net_url_fmt(&buf, &lookup_url)) < 0 ||
+                   (error = git_buf_puts(&buf, ".proxy")) < 0 ||
+                   (error = lookup_config(out, cfg, buf.ptr)) != GIT_ENOTFOUND)
+                       goto done;
 
-               if (ce && ce->value) {
-                       *proxy_url = git__strdup(ce->value);
-                       goto found;
-               }
+               if (! lookup_url.path[0])
+                       break;
+
+               url_config_trim(&lookup_url);
        }
 
-       /* http.proxy config setting */
-       if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
-               return error;
+       git_buf_clear(&buf);
 
-       if (ce && ce->value) {
-               *proxy_url = git__strdup(ce->value);
-               goto found;
-       }
+       error = lookup_config(out, cfg, "http.proxy");
+
+done:
+       git_config_free(cfg);
+       git_buf_dispose(&buf);
+       git_net_url_dispose(&lookup_url);
+       return error;
+}
+
+static int http_proxy_env(char **out, git_remote *remote, git_net_url *url)
+{
+       git_buf proxy_env = GIT_BUF_INIT, no_proxy_env = GIT_BUF_INIT;
+       bool use_ssl = (strcmp(url->scheme, "https") == 0);
+       int error;
+
+       GIT_UNUSED(remote);
 
        /* http_proxy / https_proxy environment variables */
-       error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
+       error = git__getenv(&proxy_env, use_ssl ? "https_proxy" : "http_proxy");
 
        /* try uppercase environment variables */
        if (error == GIT_ENOTFOUND)
-               error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
+               error = git__getenv(&proxy_env, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
 
-       if (error < 0) {
-               if (error == GIT_ENOTFOUND) {
-                       git_error_clear();
-                       error = 0;
-               }
+       if (error)
+               goto done;
 
-               return error;
-       }
+       /* no_proxy/NO_PROXY environment variables */
+       error = git__getenv(&no_proxy_env, "no_proxy");
 
-       *proxy_url = git_buf_detach(&val);
+       if (error == GIT_ENOTFOUND)
+               error = git__getenv(&no_proxy_env, "NO_PROXY");
 
-found:
-       GIT_ERROR_CHECK_ALLOC(*proxy_url);
-       git_config_entry_free(ce);
+       if (error && error != GIT_ENOTFOUND)
+               goto done;
+
+       if (!git_net_url_matches_pattern_list(url, no_proxy_env.ptr))
+               *out = git_buf_detach(&proxy_env);
+       else
+               error = GIT_ENOTFOUND;
+
+done:
+       git_buf_dispose(&proxy_env);
+       git_buf_dispose(&no_proxy_env);
+       return error;
+}
+
+int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url)
+{
+       int error;
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(remote);
+
+       *out = NULL;
+
+       /*
+        * Go through the possible sources for proxy configuration,
+        * Examine the various git config options first, then
+        * consult environment variables.
+        */
+       if ((error = http_proxy_config(out, remote, url)) != GIT_ENOTFOUND ||
+           (error = http_proxy_env(out, remote, url)) != GIT_ENOTFOUND)
+               return error;
 
        return 0;
 }
@@ -926,7 +1057,7 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const
        const git_strarray *custom_headers = NULL;
        const git_proxy_options *proxy = NULL;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (!remote->repo) {
                git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
@@ -1065,7 +1196,8 @@ static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *upda
        unsigned int i;
        git_remote_head *remote_ref;
 
-       assert(update_heads && fetchspec_src);
+       GIT_ASSERT_ARG(update_heads);
+       GIT_ASSERT_ARG(fetchspec_src);
 
        *out = NULL;
 
@@ -1119,7 +1251,9 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
        const char *ref_name;
        int error = 0, update;
 
-       assert(out && spec && ref);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(spec);
+       GIT_ASSERT_ARG(ref);
 
        *out = NULL;
 
@@ -1133,6 +1267,16 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
                ref_name = git_reference_name(resolved_ref);
        }
 
+       /*
+        * The ref name may be unresolvable - perhaps it's pointing to
+        * something invalid.  In this case, there is no remote head for
+        * this ref.
+        */
+       if (!ref_name) {
+               error = 0;
+               goto cleanup;
+       }
+
        if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
                goto cleanup;
 
@@ -1156,7 +1300,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git
        unsigned int i = 0;
        int error = 0;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        /* no heads, nothing to do */
        if (update_heads->length == 0)
@@ -1299,7 +1443,7 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
                        if (error == GIT_ENOTFOUND)
                                continue;
 
-                       /* if we did find a source, remove it from the candiates */
+                       /* If we did find a source, remove it from the candidates. */
                        if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
                                goto cleanup;
 
@@ -1362,7 +1506,7 @@ static int update_tips_for_spec(
                git_vector *refs,
                const char *log_message)
 {
-       int error = 0, autotag;
+       int error = 0, autotag, valid;
        unsigned int i = 0;
        git_buf refname = GIT_BUF_INIT;
        git_oid old;
@@ -1372,7 +1516,7 @@ static int update_tips_for_spec(
        git_refspec tagspec;
        git_vector update_heads;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
                return -1;
@@ -1390,7 +1534,10 @@ static int update_tips_for_spec(
                git_buf_clear(&refname);
 
                /* Ignore malformed ref names (which also saves us from tag^{} */
-               if (!git_reference_is_valid_name(head->name))
+               if (git_reference_name_is_valid(&valid, head->name) < 0)
+                       goto on_error;
+
+               if (!valid)
                        continue;
 
                /* If we have a tag, see if the auto-follow rules say to update it */
@@ -1439,6 +1586,11 @@ static int update_tips_for_spec(
                if (error < 0 && error != GIT_ENOTFOUND)
                        goto on_error;
 
+               if (!(error || error == GIT_ENOTFOUND)
+                               && !spec->force
+                               && !git_graph_descendant_of(remote->repo, &head->oid, &old))
+                       continue;
+
                if (error == GIT_ENOTFOUND) {
                        memset(&old, 0, GIT_OID_RAWSZ);
 
@@ -1499,6 +1651,7 @@ static int next_head(const git_remote *remote, git_vector *refs,
        git_remote_head *head;
        git_refspec *spec, *passive_spec;
        size_t i, j, k;
+       int valid;
 
        active = &remote->active_refspecs;
        passive = &remote->passive_refspecs;
@@ -1510,7 +1663,10 @@ static int next_head(const git_remote *remote, git_vector *refs,
        for (; i < refs->length; i++) {
                head = git_vector_get(refs, i);
 
-               if (!git_reference_is_valid_name(head->name))
+               if (git_reference_name_is_valid(&valid, head->name) < 0)
+                       return -1;
+
+               if (!valid)
                        continue;
 
                for (; j < active->length; j++) {
@@ -1657,7 +1813,7 @@ int git_remote_update_tips(
                        goto out;
        }
 
-       /* only try to do opportunisitic updates if the refpec lists differ */
+       /* Only try to do opportunistic updates if the refpec lists differ. */
        if (remote->passed_refspecs)
                error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
 
@@ -1669,7 +1825,7 @@ out:
 
 int git_remote_connected(const git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (!remote->transport || !remote->transport->is_connected)
                return 0;
@@ -1680,7 +1836,7 @@ int git_remote_connected(const git_remote *remote)
 
 int git_remote_stop(git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (remote->transport && remote->transport->cancel)
                remote->transport->cancel(remote->transport);
@@ -1690,7 +1846,7 @@ int git_remote_stop(git_remote *remote)
 
 int git_remote_disconnect(git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (git_remote_connected(remote))
                remote->transport->close(remote->transport);
@@ -1776,7 +1932,7 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo)
 
 const git_indexer_progress *git_remote_stats(git_remote *remote)
 {
-       assert(remote);
+       GIT_ASSERT_ARG_WITH_RETVAL(remote, NULL);
        return &remote->stats;
 }
 
@@ -1791,7 +1947,7 @@ int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_
        git_config *config;
        int error;
 
-       assert(repo && remote);
+       GIT_ASSERT_ARG(repo && remote);
 
        if ((error = ensure_remote_name_is_valid(remote)) < 0)
                return error;
@@ -2055,7 +2211,7 @@ int git_remote_rename(git_strarray *out, git_repository *repo, const char *name,
        git_vector problem_refspecs = GIT_VECTOR_INIT;
        git_remote *remote = NULL;
 
-       assert(out && repo && name && new_name);
+       GIT_ASSERT_ARG(out && repo && name && new_name);
 
        if ((error = git_remote_lookup(&remote, repo, name)) < 0)
                return error;
@@ -2089,24 +2245,34 @@ cleanup:
        return error;
 }
 
-int git_remote_is_valid_name(
-       const char *remote_name)
+int git_remote_name_is_valid(int *valid, const char *remote_name)
 {
        git_buf buf = GIT_BUF_INIT;
-       git_refspec refspec;
-       int error = -1;
+       git_refspec refspec = {0};
+       int error;
+
+       GIT_ASSERT(valid);
+
+       *valid = 0;
 
        if (!remote_name || *remote_name == '\0')
                return 0;
 
-       git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
+       if ((error = git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name)) < 0)
+               goto done;
+
        error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
 
+       if (!error)
+               *valid = 1;
+       else if (error == GIT_EINVALIDSPEC)
+               error = 0;
+
+done:
        git_buf_dispose(&buf);
        git_refspec__dispose(&refspec);
 
-       git_error_clear();
-       return error == 0;
+       return error;
 }
 
 git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
@@ -2221,7 +2387,7 @@ static const char *name_offset(size_t *len_out, const char *name)
        prefix_len = strlen("remote.");
        dot = strchr(name + prefix_len, '.');
 
-       assert(dot);
+       GIT_ASSERT_ARG_WITH_RETVAL(dot, NULL);
 
        *len_out = dot - name - prefix_len;
        return name + prefix_len;
@@ -2251,10 +2417,13 @@ static int remove_branch_config_related_entries(
                if (strcmp(remote_name, entry->value))
                        continue;
 
-               branch = name_offset(&branch_len, entry->name);
+               if ((branch = name_offset(&branch_len, entry->name)) == NULL) {
+                       error = -1;
+                       break;
+               }
 
                git_buf_clear(&buf);
-               if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
+               if ((error = git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch)) < 0)
                        break;
 
                if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
@@ -2264,7 +2433,7 @@ static int remove_branch_config_related_entries(
                }
 
                git_buf_clear(&buf);
-               if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
+               if ((error = git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch)) < 0)
                        break;
 
                if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
@@ -2359,7 +2528,8 @@ int git_remote_delete(git_repository *repo, const char *name)
 {
        int error;
 
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
            (error = remove_remote_tracking(repo, name)) < 0 ||
@@ -2378,7 +2548,7 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
        git_buf local_default = GIT_BUF_INIT;
        int error;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
                goto done;
@@ -2388,7 +2558,8 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
                goto done;
        }
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        /* the first one must be HEAD so if that has the symref info, we're done */
        if (heads[0]->symref_target) {
@@ -2446,7 +2617,7 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
        const git_remote_callbacks *cbs = NULL;
        git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (!remote->repo) {
                git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
@@ -2512,7 +2683,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
        const git_strarray *custom_headers = NULL;
        const git_proxy_options *proxy = NULL;
 
-       assert(remote);
+       GIT_ASSERT_ARG(remote);
 
        if (!remote->repo) {
                git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
@@ -2527,8 +2698,6 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
                proxy = &opts->proxy_opts;
        }
 
-       assert(remote);
-
        if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
                return error;
 
@@ -2555,9 +2724,9 @@ char *apply_insteadof(git_config *config, const char *url, int direction)
        git_config_entry *entry;
        git_config_iterator *iter;
 
-       assert(config);
-       assert(url);
-       assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
+       GIT_ASSERT_ARG_WITH_RETVAL(config, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(url, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH, NULL);
 
        /* Add 1 to prefix/suffix length due to the additional escaped dot */
        prefix_length = strlen(PREFIX) + 1;
@@ -2605,3 +2774,17 @@ char *apply_insteadof(git_config *config, const char *url, int direction)
 
        return result.ptr;
 }
+
+/* Deprecated functions */
+
+#ifndef GIT_DEPRECATE_HARD
+
+int git_remote_is_valid_name(const char *remote_name)
+{
+       int valid = 0;
+
+       git_remote_name_is_valid(&valid, remote_name);
+       return valid;
+}
+
+#endif
index df75ed3597b603fb6c53dc273c7ad475d42031d2..ce92db76aa5b16e391415873443957e5ca3aff81 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "refspec.h"
 #include "vector.h"
+#include "net.h"
 
 #define GIT_REMOTE_ORIGIN "origin"
 
@@ -46,7 +47,7 @@ typedef struct git_remote_connection_opts {
 int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn);
 
 int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks);
-int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url);
+int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url);
 
 git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname);
 git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname);
index 513dbd61f8362c96566c31d04e1dc33bbb75a1e2..9b3e9c9e3b13b0ecf0637e6edd579a551d5038f5 100644 (file)
@@ -93,7 +93,7 @@ static void set_odb(git_repository *repo, git_odb *odb)
                GIT_REFCOUNT_INC(odb);
        }
 
-       if ((odb = git__swap(repo->_odb, odb)) != NULL) {
+       if ((odb = git_atomic_swap(repo->_odb, odb)) != NULL) {
                GIT_REFCOUNT_OWN(odb, NULL);
                git_odb_free(odb);
        }
@@ -106,7 +106,7 @@ static void set_refdb(git_repository *repo, git_refdb *refdb)
                GIT_REFCOUNT_INC(refdb);
        }
 
-       if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) {
+       if ((refdb = git_atomic_swap(repo->_refdb, refdb)) != NULL) {
                GIT_REFCOUNT_OWN(refdb, NULL);
                git_refdb_free(refdb);
        }
@@ -119,7 +119,7 @@ static void set_config(git_repository *repo, git_config *config)
                GIT_REFCOUNT_INC(config);
        }
 
-       if ((config = git__swap(repo->_config, config)) != NULL) {
+       if ((config = git_atomic_swap(repo->_config, config)) != NULL) {
                GIT_REFCOUNT_OWN(config, NULL);
                git_config_free(config);
        }
@@ -134,7 +134,7 @@ static void set_index(git_repository *repo, git_index *index)
                GIT_REFCOUNT_INC(index);
        }
 
-       if ((index = git__swap(repo->_index, index)) != NULL) {
+       if ((index = git_atomic_swap(repo->_index, index)) != NULL) {
                GIT_REFCOUNT_OWN(index, NULL);
                git_index_free(index);
        }
@@ -142,7 +142,7 @@ static void set_index(git_repository *repo, git_index *index)
 
 int git_repository__cleanup(git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        git_repository_submodule_cache_clear(repo);
        git_cache_clear(&repo->objects);
@@ -186,6 +186,63 @@ void git_repository_free(git_repository *repo)
        git__free(repo);
 }
 
+/* Check if we have a separate commondir (e.g. we have a worktree) */
+static int lookup_commondir(bool *separate, git_buf *commondir, git_buf *repository_path)
+{
+       git_buf common_link  = GIT_BUF_INIT;
+       int error;
+
+       /*
+        * If there's no commondir file, the repository path is the
+        * common path, but it needs a trailing slash.
+        */
+       if (!git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
+               if ((error = git_buf_set(commondir, repository_path->ptr, repository_path->size)) == 0)
+                   error = git_path_to_dir(commondir);
+
+               *separate = false;
+               goto done;
+       }
+
+       *separate = true;
+
+       if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
+           (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
+               goto done;
+
+       git_buf_rtrim(&common_link);
+       if (git_path_is_relative(common_link.ptr)) {
+               if ((error = git_buf_joinpath(commondir, repository_path->ptr, common_link.ptr)) < 0)
+                       goto done;
+       } else {
+               git_buf_swap(commondir, &common_link);
+       }
+
+       git_buf_dispose(&common_link);
+
+       /* Make sure the commondir path always has a trailing slash */
+       error = git_path_prettify_dir(commondir, commondir->ptr, NULL);
+
+done:
+       return error;
+}
+
+GIT_INLINE(int) validate_repo_path(git_buf *path)
+{
+       /*
+        * The longest static path in a repository (or commondir) is the
+        * packed refs file.  (Loose refs may be longer since they
+        * include the reference name, but will be validated when the
+        * path is constructed.)
+        */
+       static size_t suffix_len =
+               CONST_STRLEN("objects/pack/pack-.pack.lock") +
+               GIT_OID_HEXSZ;
+
+       return git_path_validate_filesystem_with_suffix(
+               path->ptr, path->size, suffix_len);
+}
+
 /*
  * Git repository open methods
  *
@@ -193,48 +250,30 @@ void git_repository_free(git_repository *repo)
  */
 static int is_valid_repository_path(bool *out, git_buf *repository_path, git_buf *common_path)
 {
+       bool separate_commondir = false;
        int error;
 
        *out = false;
 
-       /* Check if we have a separate commondir (e.g. we have a
-        * worktree) */
-       if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
-               git_buf common_link  = GIT_BUF_INIT;
-
-               if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
-                   (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
-                       return error;
-
-               git_buf_rtrim(&common_link);
-               if (git_path_is_relative(common_link.ptr)) {
-                       if ((error = git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr)) < 0)
-                               return error;
-               } else {
-                       git_buf_swap(common_path, &common_link);
-               }
-
-               git_buf_dispose(&common_link);
-       }
-       else {
-               if ((error = git_buf_set(common_path, repository_path->ptr, repository_path->size)) < 0)
-                       return error;
-       }
-
-       /* Make sure the commondir path always has a trailing * slash */
-       if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
-               if ((error = git_buf_putc(common_path, '/')) < 0)
-                       return error;
+       if ((error = lookup_commondir(&separate_commondir, common_path, repository_path)) < 0)
+               return error;
 
        /* Ensure HEAD file exists */
        if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
                return 0;
+
        /* Check files in common dir */
        if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
                return 0;
        if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
                return 0;
 
+       /* Ensure the repo (and commondir) are valid paths */
+       if ((error = validate_repo_path(common_path)) < 0 ||
+           (separate_commondir &&
+            (error = validate_repo_path(repository_path)) < 0))
+               return error;
+
        *out = true;
        return 0;
 }
@@ -368,7 +407,7 @@ static size_t find_ceiling_dir_offset(
        const char *ceil, *sep;
        size_t len, max_len = 0, min_len;
 
-       assert(path);
+       GIT_ASSERT_ARG(path);
 
        min_len = (size_t)(git_path_root(path) + 1);
 
@@ -414,7 +453,8 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
        git_buf file = GIT_BUF_INIT;
        size_t  prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);
 
-       assert(path_out && file_path);
+       GIT_ASSERT_ARG(path_out);
+       GIT_ASSERT_ARG(file_path);
 
        if (git_futils_readbuffer(&file, file_path) < 0)
                return -1;
@@ -901,7 +941,8 @@ int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *w
        size_t len;
        int err;
 
-       assert(repo_out && wt);
+       GIT_ASSERT_ARG(repo_out);
+       GIT_ASSERT_ARG(wt);
 
        *repo_out = NULL;
        len = strlen(wt->gitlink_path);
@@ -945,10 +986,12 @@ int git_repository_discover(
        const char *ceiling_dirs)
 {
        uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0;
+       int error;
 
-       assert(start_path);
+       GIT_ASSERT_ARG(start_path);
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        return find_repo(out, NULL, NULL, NULL, start_path, flags, ceiling_dirs);
 }
@@ -965,7 +1008,7 @@ static int load_config(
        git_buf config_path = GIT_BUF_INIT;
        git_config *cfg = NULL;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        if ((error = git_config_new(&cfg)) < 0)
                return error;
@@ -1050,8 +1093,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
                if (!error) {
                        GIT_REFCOUNT_OWN(config, repo);
 
-                       config = git__compare_and_swap(&repo->_config, NULL, config);
-                       if (config != NULL) {
+                       if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) {
                                GIT_REFCOUNT_OWN(config, NULL);
                                git_config_free(config);
                        }
@@ -1089,7 +1131,9 @@ int git_repository_config_snapshot(git_config **out, git_repository *repo)
 
 int git_repository_set_config(git_repository *repo, git_config *config)
 {
-       assert(repo && config);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(config);
+
        set_config(repo, config);
        return 0;
 }
@@ -1098,9 +1142,11 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
 {
        int error = 0;
 
-       assert(repo && out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(out);
 
-       if (repo->_odb == NULL) {
+       *out = git_atomic_load(repo->_odb);
+       if (*out == NULL) {
                git_buf odb_path = GIT_BUF_INIT;
                git_odb *odb;
 
@@ -1117,16 +1163,15 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
                        return error;
                }
 
-               odb = git__compare_and_swap(&repo->_odb, NULL, odb);
-               if (odb != NULL) {
+               if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) {
                        GIT_REFCOUNT_OWN(odb, NULL);
                        git_odb_free(odb);
                }
 
                git_buf_dispose(&odb_path);
+               *out = git_atomic_load(repo->_odb);
        }
 
-       *out = repo->_odb;
        return error;
 }
 
@@ -1141,7 +1186,9 @@ int git_repository_odb(git_odb **out, git_repository *repo)
 
 int git_repository_set_odb(git_repository *repo, git_odb *odb)
 {
-       assert(repo && odb);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(odb);
+
        set_odb(repo, odb);
        return 0;
 }
@@ -1150,7 +1197,8 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
 {
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        if (repo->_refdb == NULL) {
                git_refdb *refdb;
@@ -1159,8 +1207,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
                if (!error) {
                        GIT_REFCOUNT_OWN(refdb, repo);
 
-                       refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
-                       if (refdb != NULL) {
+                       if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) {
                                GIT_REFCOUNT_OWN(refdb, NULL);
                                git_refdb_free(refdb);
                        }
@@ -1182,7 +1229,9 @@ int git_repository_refdb(git_refdb **out, git_repository *repo)
 
 int git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
 {
-       assert(repo && refdb);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(refdb);
+
        set_refdb(repo, refdb);
        return 0;
 }
@@ -1191,7 +1240,8 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
 {
        int error = 0;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        if (repo->_index == NULL) {
                git_buf index_path = GIT_BUF_INIT;
@@ -1204,8 +1254,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
                if (!error) {
                        GIT_REFCOUNT_OWN(index, repo);
 
-                       index = git__compare_and_swap(&repo->_index, NULL, index);
-                       if (index != NULL) {
+                       if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) {
                                GIT_REFCOUNT_OWN(index, NULL);
                                git_index_free(index);
                        }
@@ -1232,7 +1281,7 @@ int git_repository_index(git_index **out, git_repository *repo)
 
 int git_repository_set_index(git_repository *repo, git_index *index)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
        set_index(repo, index);
        return 0;
 }
@@ -1378,15 +1427,60 @@ static int check_repositoryformatversion(int *version, git_config *config)
        return 0;
 }
 
+static const char *builtin_extensions[] = {
+       "noop"
+};
+
+static git_vector user_extensions = GIT_VECTOR_INIT;
+
 static int check_valid_extension(const git_config_entry *entry, void *payload)
 {
+       git_buf cfg = GIT_BUF_INIT;
+       bool reject;
+       const char *extension;
+       size_t i;
+       int error = 0;
+
        GIT_UNUSED(payload);
 
-       if (!strcmp(entry->name, "extensions.noop"))
-               return 0;
+       git_vector_foreach (&user_extensions, i, extension) {
+               git_buf_clear(&cfg);
+
+               /*
+                * Users can specify that they don't want to support an
+                * extension with a '!' prefix.
+                */
+               if ((reject = (extension[0] == '!')) == true)
+                       extension = &extension[1];
+
+               if ((error = git_buf_printf(&cfg, "extensions.%s", extension)) < 0)
+                       goto done;
+
+               if (strcmp(entry->name, cfg.ptr) == 0) {
+                       if (reject)
+                               goto fail;
+
+                       goto done;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) {
+               extension = builtin_extensions[i];
 
+               if ((error = git_buf_printf(&cfg, "extensions.%s", extension)) < 0)
+                       goto done;
+
+               if (strcmp(entry->name, cfg.ptr) == 0)
+                       goto done;
+       }
+
+fail:
        git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name);
-       return -1;
+       error = -1;
+
+done:
+       git_buf_dispose(&cfg);
+       return error;
 }
 
 static int check_extensions(git_config *config, int version)
@@ -1397,6 +1491,70 @@ static int check_extensions(git_config *config, int version)
        return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
 }
 
+int git_repository__extensions(char ***out, size_t *out_len)
+{
+       git_vector extensions;
+       const char *builtin, *user;
+       char *extension;
+       size_t i, j;
+
+       if (git_vector_init(&extensions, 8, NULL) < 0)
+               return -1;
+
+       for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) {
+               bool match = false;
+
+               builtin = builtin_extensions[i];
+
+               git_vector_foreach (&user_extensions, j, user) {
+                       if (user[0] == '!' && strcmp(builtin, &user[1]) == 0) {
+                               match = true;
+                               break;
+                       }
+               }
+
+               if (match)
+                       continue;
+
+               if ((extension = git__strdup(builtin)) == NULL ||
+                   git_vector_insert(&extensions, extension) < 0)
+                       return -1;
+       }
+
+       git_vector_foreach (&user_extensions, i, user) {
+               if (user[0] == '!')
+                       continue;
+
+               if ((extension = git__strdup(user)) == NULL ||
+                   git_vector_insert(&extensions, extension) < 0)
+                       return -1;
+       }
+
+       *out = (char **)git_vector_detach(out_len, NULL, &extensions);
+       return 0;
+}
+
+int git_repository__set_extensions(const char **extensions, size_t len)
+{
+       char *extension;
+       size_t i;
+
+       git_repository__free_extensions();
+
+       for (i = 0; i < len; i++) {
+               if ((extension = git__strdup(extensions[i])) == NULL ||
+                   git_vector_insert(&user_extensions, extension) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+void git_repository__free_extensions(void)
+{
+       git_vector_free_deep(&user_extensions);
+}
+
 int git_repository_create_head(const char *git_dir, const char *ref_name)
 {
        git_buf ref_path = GIT_BUF_INIT;
@@ -2078,7 +2236,8 @@ static int repo_init_head(const char *repo_dir, const char *given)
        if (given) {
                initial_head = given;
        } else if ((error = git_config_open_default(&cfg)) >= 0 &&
-                  (error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0) {
+                  (error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 &&
+                  *cfg_branch.ptr) {
                initial_head = cfg_branch.ptr;
        }
 
@@ -2130,7 +2289,9 @@ int git_repository_init_ext(
        bool is_valid;
        int error;
 
-       assert(out && given_repo && opts);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(given_repo);
+       GIT_ASSERT_ARG(opts);
 
        GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
 
@@ -2206,7 +2367,8 @@ int git_repository_head_detached_for_worktree(git_repository *repo, const char *
        git_reference *ref = NULL;
        int error;
 
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0)
                goto out;
@@ -2223,7 +2385,7 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
        git_reference *head;
        int error;
 
-       assert(head_out);
+       GIT_ASSERT_ARG(head_out);
 
        if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
                return error;
@@ -2246,7 +2408,9 @@ int git_repository_head_for_worktree(git_reference **out, git_repository *repo,
        git_reference *head = NULL;
        int error;
 
-       assert(out && repo && name);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        *out = NULL;
 
@@ -2280,6 +2444,12 @@ int git_repository_foreach_worktree(git_repository *repo,
        int error;
        size_t i;
 
+       /* apply operation to repository supplied when commondir is empty, implying there's
+        * no linked worktrees to iterate, which can occur when using custom odb/refdb
+        */
+       if (!repo->commondir)
+               return cb(repo, payload);
+
        if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
            (error = cb(worktree_repo, payload) != 0))
                goto out;
@@ -2334,21 +2504,19 @@ int git_repository_head_unborn(git_repository *repo)
        return 0;
 }
 
-static int at_least_one_cb(const char *refname, void *payload)
-{
-       GIT_UNUSED(refname);
-       GIT_UNUSED(payload);
-       return GIT_PASSTHROUGH;
-}
-
 static int repo_contains_no_reference(git_repository *repo)
 {
-       int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
+       git_reference_iterator *iter;
+       const char *refname;
+       int error;
 
-       if (error == GIT_PASSTHROUGH)
-               return 0;
+       if ((error = git_reference_iterator_new(&iter, repo)) < 0)
+               return error;
 
-       if (!error)
+       error = git_reference_next_name(&refname, iter);
+       git_reference_iterator_free(iter);
+
+       if (error == GIT_ITEROVER)
                return 1;
 
        return error;
@@ -2359,15 +2527,16 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
        git_config *config;
        git_config_entry *entry = NULL;
        const char *branch;
-       int error;
+       int valid, error;
 
        if ((error = git_repository_config__weakptr(&config, repo)) < 0)
                return error;
 
-       if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0) {
+       if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 &&
+               *entry->value) {
                branch = entry->value;
        }
-       else if (error == GIT_ENOTFOUND) {
+       else if (!error || error == GIT_ENOTFOUND) {
                branch = GIT_BRANCH_DEFAULT;
        }
        else {
@@ -2375,11 +2544,12 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
        }
 
        if ((error = git_buf_puts(out, GIT_REFS_HEADS_DIR)) < 0 ||
-           (error = git_buf_puts(out, branch)) < 0)
+           (error = git_buf_puts(out, branch)) < 0 ||
+           (error = git_reference_name_is_valid(&valid, out->ptr)) < 0)
            goto done;
 
-       if (!git_reference_is_valid_name(out->ptr)) {
-               git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid reference name");
+       if (!valid) {
+               git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name");
                error = -1;
        }
 
@@ -2459,13 +2629,13 @@ int git_repository_item_path(git_buf *out, const git_repository *repo, git_repos
 
 const char *git_repository_path(const git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
        return repo->gitdir;
 }
 
 const char *git_repository_workdir(const git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
 
        if (repo->is_bare)
                return NULL;
@@ -2473,9 +2643,25 @@ const char *git_repository_workdir(const git_repository *repo)
        return repo->workdir;
 }
 
+int git_repository_workdir_path(
+       git_buf *out, git_repository *repo, const char *path)
+{
+       int error;
+
+       if (!repo->workdir) {
+               git_error_set(GIT_ERROR_REPOSITORY, "repository has no working directory");
+               return GIT_EBAREREPO;
+       }
+
+       if (!(error = git_buf_joinpath(out, repo->workdir, path)))
+               error = git_path_validate_workdir_buf(repo, out);
+
+       return error;
+}
+
 const char *git_repository_commondir(const git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
        return repo->commondir;
 }
 
@@ -2485,7 +2671,8 @@ int git_repository_set_workdir(
        int error = 0;
        git_buf path = GIT_BUF_INIT;
 
-       assert(repo && workdir);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(workdir);
 
        if (git_path_prettify_dir(&path, workdir, NULL) < 0)
                return -1;
@@ -2525,13 +2712,13 @@ int git_repository_set_workdir(
 
 int git_repository_is_bare(const git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
        return repo->is_bare;
 }
 
 int git_repository_is_worktree(const git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
        return repo->is_worktree;
 }
 
@@ -2540,7 +2727,7 @@ int git_repository_set_bare(git_repository *repo)
        int error;
        git_config *config;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        if (repo->is_bare)
                return 0;
@@ -2608,7 +2795,8 @@ int git_repository_message(git_buf *out, git_repository *repo)
        struct stat st;
        int error;
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
                return -1;
@@ -2652,31 +2840,36 @@ int git_repository_hashfile(
        git_file fd = -1;
        uint64_t len;
        git_buf full_path = GIT_BUF_INIT;
+       const char *workdir = git_repository_workdir(repo);
 
-       assert(out && path && repo); /* as_path can be NULL */
+        /* as_path can be NULL */
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(path);
+       GIT_ASSERT_ARG(repo);
 
-       /* At some point, it would be nice if repo could be NULL to just
-        * apply filter rules defined in system and global files, but for
-        * now that is not possible because git_filters_load() needs it.
-        */
-
-       error = git_path_join_unrooted(
-               &full_path, path, git_repository_workdir(repo), NULL);
-       if (error < 0)
+       if ((error = git_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 ||
+           (error = git_path_validate_workdir_buf(repo, &full_path)) < 0)
                return error;
 
-       if (!as_path)
-               as_path = path;
+       /*
+        * NULL as_path means that we should derive it from the
+        * given path.
+        */
+       if (!as_path) {
+               if (workdir && !git__prefixcmp(full_path.ptr, workdir))
+                       as_path = full_path.ptr + strlen(workdir);
+               else
+                       as_path = "";
+       }
 
        /* passing empty string for "as_path" indicated --no-filters */
        if (strlen(as_path) > 0) {
                error = git_filter_list_load(
                        &fl, repo, NULL, as_path,
                        GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
+
                if (error < 0)
                        return error;
-       } else {
-               error = 0;
        }
 
        /* at this point, error is a count of the number of loaded filters */
@@ -2738,7 +2931,8 @@ static int detach(git_repository *repo, const git_oid *id, const char *new)
        git_object *object = NULL, *peeled = NULL;
        git_reference *new_head = NULL, *current = NULL;
 
-       assert(repo && id);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(id);
 
        if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
                return error;
@@ -2767,14 +2961,15 @@ cleanup:
 }
 
 int git_repository_set_head(
-       git_repositoryrepo,
-       const charrefname)
+       git_repository *repo,
+       const char *refname)
 {
        git_reference *ref = NULL, *current = NULL, *new_head = NULL;
        git_buf log_message = GIT_BUF_INIT;
        int error;
 
-       assert(repo && refname);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(refname);
 
        if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
                return error;
@@ -2816,8 +3011,8 @@ cleanup:
 }
 
 int git_repository_set_head_detached(
-       git_repositoryrepo,
-       const git_oidcommitish)
+       git_repository *repo,
+       const git_oid *commitish)
 {
        return detach(repo, commitish, NULL);
 }
@@ -2826,19 +3021,20 @@ int git_repository_set_head_detached_from_annotated(
        git_repository *repo,
        const git_annotated_commit *commitish)
 {
-       assert(repo && commitish);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(commitish);
 
        return detach(repo, git_annotated_commit_id(commitish), commitish->description);
 }
 
-int git_repository_detach_head(git_repositoryrepo)
+int git_repository_detach_head(git_repository *repo)
 {
        git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
        git_object *object = NULL;
        git_buf log_message = GIT_BUF_INIT;
        int error;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
                return error;
@@ -2873,7 +3069,7 @@ int git_repository_state(git_repository *repo)
        git_buf repo_path = GIT_BUF_INIT;
        int state = GIT_REPOSITORY_STATE_NONE;
 
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        if (git_buf_puts(&repo_path, repo->gitdir) < 0)
                return -1;
@@ -2950,7 +3146,7 @@ static const char *state_files[] = {
 
 int git_repository_state_cleanup(git_repository *repo)
 {
-       assert(repo);
+       GIT_ASSERT_ARG(repo);
 
        return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
 }
@@ -3016,8 +3212,8 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char
                GIT_ERROR_CHECK_ALLOC(tmp_email);
        }
 
-       tmp_name = git__swap(repo->ident_name, tmp_name);
-       tmp_email = git__swap(repo->ident_email, tmp_email);
+       tmp_name = git_atomic_swap(repo->ident_name, tmp_name);
+       tmp_email = git_atomic_swap(repo->ident_email, tmp_email);
 
        git__free(tmp_name);
        git__free(tmp_email);
@@ -3027,28 +3223,16 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char
 
 int git_repository_submodule_cache_all(git_repository *repo)
 {
-       int error;
-
-       assert(repo);
-
-       if ((error = git_strmap_new(&repo->submodule_cache)))
-               return error;
-
-       error = git_submodule__map(repo, repo->submodule_cache);
-       return error;
+       GIT_ASSERT_ARG(repo);
+       return git_submodule_cache_init(&repo->submodule_cache, repo);
 }
 
 int git_repository_submodule_cache_clear(git_repository *repo)
 {
-       git_submodule *sm;
-       assert(repo);
-       if (repo->submodule_cache == NULL) {
-               return 0;
-       }
-       git_strmap_foreach_value(repo->submodule_cache, sm, {
-               git_submodule_free(sm);
-       });
-       git_strmap_free(repo->submodule_cache);
-       repo->submodule_cache = 0;
-       return 0;
+       int error = 0;
+       GIT_ASSERT_ARG(repo);
+
+       error = git_submodule_cache_free(repo->submodule_cache);
+       repo->submodule_cache = NULL;
+       return error;
 }
index de009ba5e8b752e95ca395fae12d35895404d498..cbc160140f39266268e4583369de407fb52e7e2b 100644 (file)
@@ -51,6 +51,7 @@ typedef enum {
        GIT_CONFIGMAP_PROTECTHFS,       /* core.protectHFS */
        GIT_CONFIGMAP_PROTECTNTFS,      /* core.protectNTFS */
        GIT_CONFIGMAP_FSYNCOBJECTFILES, /* core.fsyncObjectFiles */
+       GIT_CONFIGMAP_LONGPATHS,        /* core.longpaths */
        GIT_CONFIGMAP_CACHE_MAX
 } git_configmap_item;
 
@@ -116,6 +117,8 @@ typedef enum {
        GIT_PROTECTNTFS_DEFAULT = GIT_CONFIGMAP_TRUE,
        /* core.fsyncObjectFiles */
        GIT_FSYNCOBJECTFILES_DEFAULT = GIT_CONFIGMAP_FALSE,
+       /* core.longpaths */
+       GIT_LONGPATHS_DEFAULT = GIT_CONFIGMAP_FALSE,
 } git_configmap_value;
 
 /* internal repository init flags */
@@ -152,9 +155,9 @@ struct git_repository {
 
        unsigned int lru_counter;
 
-       git_atomic attr_session_key;
+       git_atomic32 attr_session_key;
 
-       git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
+       intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
        git_strmap *submodule_cache;
 };
 
@@ -238,4 +241,16 @@ bool git_repository__reserved_names(
  */
 int git_repository_initialbranch(git_buf *out, git_repository *repo);
 
+/*
+ * Given a relative `path`, this makes it absolute based on the
+ * repository's working directory.  This will perform validation
+ * to ensure that the path is not longer than MAX_PATH on Windows
+ * (unless `core.longpaths` is set in the repo config).
+ */
+int git_repository_workdir_path(git_buf *out, git_repository *repo, const char *path);
+
+int git_repository__extensions(char ***out, size_t *out_len);
+int git_repository__set_extensions(const char **extensions, size_t len);
+void git_repository__free_extensions(void);
+
 #endif
index ca6a5bd73cf173ff15970342153a77c6424bb13d..f21a620c653fedb8d8d465946a04e97c21909fa8 100644 (file)
@@ -22,7 +22,7 @@
 int git_reset_default(
        git_repository *repo,
        const git_object *target,
-       const git_strarraypathspecs)
+       const git_strarray *pathspecs)
 {
        git_object *commit = NULL;
        git_tree *tree = NULL;
@@ -33,7 +33,7 @@ int git_reset_default(
        int error;
        git_index *index = NULL;
 
-       assert(pathspecs != NULL && pathspecs->count > 0);
+       GIT_ASSERT_ARG(pathspecs && pathspecs->count > 0);
 
        memset(&entry, 0, sizeof(git_index_entry));
 
@@ -62,10 +62,10 @@ int git_reset_default(
        for (i = 0, max_i = git_diff_num_deltas(diff); i < max_i; ++i) {
                const git_diff_delta *delta = git_diff_get_delta(diff, i);
 
-               assert(delta->status == GIT_DELTA_ADDED ||
-                       delta->status == GIT_DELTA_MODIFIED ||
-                       delta->status == GIT_DELTA_CONFLICTED ||
-                       delta->status == GIT_DELTA_DELETED);
+               GIT_ASSERT(delta->status == GIT_DELTA_ADDED ||
+                          delta->status == GIT_DELTA_MODIFIED ||
+                          delta->status == GIT_DELTA_CONFLICTED ||
+                          delta->status == GIT_DELTA_DELETED);
 
                error = git_index_conflict_remove(index, delta->old_file.path);
                if (error < 0) {
@@ -113,7 +113,8 @@ static int reset(
        git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
        git_buf log_message = GIT_BUF_INIT;
 
-       assert(repo && target);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(target);
 
        if (checkout_opts)
                opts = *checkout_opts;
index b84bc7d79a0c7d7a2b4a60c21bffa93e4c78f50c..683f0d70d8b15f93f1770ac6a56c4c2d20756149 100644 (file)
@@ -129,7 +129,10 @@ int git_revert_commit(
        git_tree *parent_tree = NULL, *our_tree = NULL, *revert_tree = NULL;
        int parent = 0, error = 0;
 
-       assert(out && repo && revert_commit && our_commit);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(revert_commit);
+       GIT_ASSERT_ARG(our_commit);
 
        if (git_commit_parentcount(revert_commit) > 1) {
                if (!mainline)
@@ -180,7 +183,8 @@ int git_revert(
        git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
        int error;
 
-       assert(repo && commit);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(commit);
 
        GIT_ERROR_CHECK_VERSION(given_opts, GIT_REVERT_OPTIONS_VERSION, "git_revert_options");
 
index 1cc8b97f52b17e0b8027ebee89dcfe8e50135b96..b4d5d475938cc2df9d75cc9467b723205adda956 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "git2.h"
 
-static int maybe_sha_or_abbrev(git_object** out, git_repository *repo, const char *spec, size_t speclen)
+static int maybe_sha_or_abbrev(git_object **out, git_repository *repo, const char *spec, size_t speclen)
 {
        git_oid oid;
 
@@ -24,7 +24,7 @@ static int maybe_sha_or_abbrev(git_object** out, git_repository *repo, const cha
        return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY);
 }
 
-static int maybe_sha(git_object** out, git_repository *repo, const char *spec)
+static int maybe_sha(git_object **out, git_repository *repo, const char *spec)
 {
        size_t speclen = strlen(spec);
 
@@ -34,7 +34,7 @@ static int maybe_sha(git_object** out, git_repository *repo, const char *spec)
        return maybe_sha_or_abbrev(out, repo, spec, speclen);
 }
 
-static int maybe_abbrev(git_object** out, git_repository *repo, const char *spec)
+static int maybe_abbrev(git_object **out, git_repository *repo, const char *spec)
 {
        size_t speclen = strlen(spec);
 
@@ -310,14 +310,14 @@ cleanup:
        return error;
 }
 
-static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repositoryrepo, const char *curly_braces_content)
+static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repository *repo, const char *curly_braces_content)
 {
        bool is_numeric;
        int parsed = 0, error = -1;
        git_buf identifier = GIT_BUF_INIT;
        git_time_t timestamp;
 
-       assert(*out == NULL);
+       GIT_ASSERT(*out == NULL);
 
        if (git_buf_put(&identifier, spec, identifier_len) < 0)
                return -1;
@@ -524,7 +524,7 @@ static int extract_curly_braces_content(git_buf *buf, const char *spec, size_t *
 {
        git_buf_clear(buf);
 
-       assert(spec[*pos] == '^' || spec[*pos] == '@');
+       GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '@');
 
        (*pos)++;
 
@@ -550,7 +550,7 @@ static int extract_path(git_buf *buf, const char *spec, size_t *pos)
 {
        git_buf_clear(buf);
 
-       assert(spec[*pos] == ':');
+       GIT_ASSERT_ARG(spec[*pos] == ':');
 
        (*pos)++;
 
@@ -568,7 +568,7 @@ static int extract_how_many(int *n, const char *spec, size_t *pos)
        int parsed, accumulated;
        char kind = spec[*pos];
 
-       assert(spec[*pos] == '^' || spec[*pos] == '~');
+       GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '~');
 
        accumulated = 0;
 
@@ -676,7 +676,10 @@ static int revparse(
 
        bool should_return_reference = true;
 
-       assert(object_out && reference_out && repo && spec);
+       GIT_ASSERT_ARG(object_out);
+       GIT_ASSERT_ARG(reference_out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(spec);
 
        *object_out = NULL;
        *reference_out = NULL;
@@ -882,14 +885,16 @@ int git_revparse(
        const char *dotdot;
        int error = 0;
 
-       assert(revspec && repo && spec);
+       GIT_ASSERT_ARG(revspec);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(spec);
 
        memset(revspec, 0x0, sizeof(*revspec));
 
        if ((dotdot = strstr(spec, "..")) != NULL) {
                char *lstr;
                const char *rstr;
-               revspec->flags = GIT_REVPARSE_RANGE;
+               revspec->flags = GIT_REVSPEC_RANGE;
 
                /*
                 * Following git.git, don't allow '..' because it makes command line
@@ -905,7 +910,7 @@ int git_revparse(
                lstr = git__substrdup(spec, dotdot - spec);
                rstr = dotdot + 2;
                if (dotdot[2] == '.') {
-                       revspec->flags |= GIT_REVPARSE_MERGE_BASE;
+                       revspec->flags |= GIT_REVSPEC_MERGE_BASE;
                        rstr++;
                }
 
@@ -923,7 +928,7 @@ int git_revparse(
 
                git__free((void*)lstr);
        } else {
-               revspec->flags = GIT_REVPARSE_SINGLE;
+               revspec->flags = GIT_REVSPEC_SINGLE;
                error = git_revparse_single(&revspec->from, repo, spec);
        }
 
index 1efb938bd3e0f56608dfbf1bfb5dd2d809265baa..a686a9f6fa91012de237b51b552930c4bf0f3a86 100644 (file)
@@ -99,7 +99,8 @@ int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
 
-       assert(walk && oid);
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(oid);
 
        return git_revwalk__push_commit(walk, oid, &opts);
 }
@@ -108,7 +109,9 @@ int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
 int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk && oid);
+
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(oid);
 
        opts.uninteresting = 1;
        return git_revwalk__push_commit(walk, oid, &opts);
@@ -133,7 +136,8 @@ int git_revwalk__push_glob(git_revwalk *walk, const char *glob, const git_revwal
        git_reference_iterator *iter;
        size_t wildcard;
 
-       assert(walk && glob);
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(glob);
 
        if (given_opts)
                memcpy(&opts, given_opts, sizeof(opts));
@@ -172,7 +176,9 @@ out:
 int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk && glob);
+
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(glob);
 
        return git_revwalk__push_glob(walk, glob, &opts);
 }
@@ -180,7 +186,9 @@ int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
 int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk && glob);
+
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(glob);
 
        opts.uninteresting = 1;
        return git_revwalk__push_glob(walk, glob, &opts);
@@ -189,7 +197,8 @@ int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
 int git_revwalk_push_head(git_revwalk *walk)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk);
+
+       GIT_ASSERT_ARG(walk);
 
        return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
 }
@@ -197,7 +206,8 @@ int git_revwalk_push_head(git_revwalk *walk)
 int git_revwalk_hide_head(git_revwalk *walk)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk);
+
+       GIT_ASSERT_ARG(walk);
 
        opts.uninteresting = 1;
        return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
@@ -206,7 +216,9 @@ int git_revwalk_hide_head(git_revwalk *walk)
 int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk && refname);
+
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(refname);
 
        return git_revwalk__push_ref(walk, refname, &opts);
 }
@@ -226,7 +238,7 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range)
                goto out;
        }
 
-       if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
+       if (revspec.flags & GIT_REVSPEC_MERGE_BASE) {
                /* TODO: support "<commit>...<commit>" */
                git_error_set(GIT_ERROR_INVALID, "symmetric differences not implemented in revwalk");
                error = GIT_EINVALIDSPEC;
@@ -249,7 +261,10 @@ out:
 int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
 {
        git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
-       assert(walk && refname);
+
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(refname);
+
        opts.uninteresting = 1;
        return git_revwalk__push_ref(walk, refname, &opts);
 }
@@ -694,13 +709,14 @@ void git_revwalk_free(git_revwalk *walk)
 
 git_repository *git_revwalk_repository(git_revwalk *walk)
 {
-       assert(walk);
+       GIT_ASSERT_ARG_WITH_RETVAL(walk, NULL);
+
        return walk->repo;
 }
 
 int git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
 {
-       assert(walk);
+       GIT_ASSERT_ARG(walk);
 
        if (walk->walking)
                git_revwalk_reset(walk);
@@ -732,7 +748,8 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk)
        int error;
        git_commit_list_node *next;
 
-       assert(walk && oid);
+       GIT_ASSERT_ARG(walk);
+       GIT_ASSERT_ARG(oid);
 
        if (!walk->walking) {
                if ((error = prepare_walk(walk)) < 0)
@@ -757,7 +774,7 @@ int git_revwalk_reset(git_revwalk *walk)
 {
        git_commit_list_node *commit;
 
-       assert(walk);
+       GIT_ASSERT_ARG(walk);
 
        git_oidmap_foreach_value(walk->commits, commit, {
                commit->seen = 0;
@@ -787,7 +804,7 @@ int git_revwalk_add_hide_cb(
        git_revwalk_hide_cb hide_cb,
        void *payload)
 {
-       assert(walk);
+       GIT_ASSERT_ARG(walk);
 
        if (walk->walking)
                git_revwalk_reset(walk);
diff --git a/src/runtime.c b/src/runtime.c
new file mode 100644 (file)
index 0000000..c05dee8
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+#include "runtime.h"
+
+static git_runtime_shutdown_fn shutdown_callback[32];
+static git_atomic32 shutdown_callback_count;
+
+static git_atomic32 init_count;
+
+static int init_common(git_runtime_init_fn init_fns[], size_t cnt)
+{
+       size_t i;
+       int ret;
+
+       /* Initialize subsystems that have global state */
+       for (i = 0; i < cnt; i++) {
+               if ((ret = init_fns[i]()) != 0)
+                       break;
+       }
+
+       GIT_MEMORY_BARRIER;
+
+       return ret;
+}
+
+static void shutdown_common(void)
+{
+       git_runtime_shutdown_fn cb;
+       int pos;
+
+       for (pos = git_atomic32_get(&shutdown_callback_count);
+            pos > 0;
+            pos = git_atomic32_dec(&shutdown_callback_count)) {
+               cb = git_atomic_swap(shutdown_callback[pos - 1], NULL);
+
+               if (cb != NULL)
+                       cb();
+       }
+}
+
+int git_runtime_shutdown_register(git_runtime_shutdown_fn callback)
+{
+       int count = git_atomic32_inc(&shutdown_callback_count);
+
+       if (count > (int)ARRAY_SIZE(shutdown_callback) || count == 0) {
+               git_error_set(GIT_ERROR_INVALID,
+                             "too many shutdown callbacks registered");
+               git_atomic32_dec(&shutdown_callback_count);
+               return -1;
+       }
+
+       shutdown_callback[count - 1] = callback;
+
+       return 0;
+}
+
+#if defined(GIT_THREADS) && defined(GIT_WIN32)
+
+/*
+ * On Win32, we use a spinlock to provide locking semantics.  This is
+ * lighter-weight than a proper critical section.
+ */
+static volatile LONG init_spinlock = 0;
+
+GIT_INLINE(int) init_lock(void)
+{
+       while (InterlockedCompareExchange(&init_spinlock, 1, 0)) { Sleep(0); }
+       return 0;
+}
+
+GIT_INLINE(int) init_unlock(void)
+{
+       InterlockedExchange(&init_spinlock, 0);
+       return 0;
+}
+
+#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
+
+/*
+ * On POSIX, we need to use a proper mutex for locking.  We might prefer
+ * a spinlock here, too, but there's no static initializer for a
+ * pthread_spinlock_t.
+ */
+static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+GIT_INLINE(int) init_lock(void)
+{
+       return pthread_mutex_lock(&init_mutex) == 0 ? 0 : -1;
+}
+
+GIT_INLINE(int) init_unlock(void)
+{
+       return pthread_mutex_unlock(&init_mutex) == 0 ? 0 : -1;
+}
+
+#elif defined(GIT_THREADS)
+# error unknown threading model
+#else
+
+# define init_lock() git__noop()
+# define init_unlock() git__noop()
+
+#endif
+
+int git_runtime_init(git_runtime_init_fn init_fns[], size_t cnt)
+{
+       int ret;
+
+       if (init_lock() < 0)
+               return -1;
+
+       /* Only do work on a 0 -> 1 transition of the refcount */
+       if ((ret = git_atomic32_inc(&init_count)) == 1) {
+               if (init_common(init_fns, cnt) < 0)
+                       ret = -1;
+       }
+
+       if (init_unlock() < 0)
+               return -1;
+
+       return ret;
+}
+
+int git_runtime_init_count(void)
+{
+       int ret;
+
+       if (init_lock() < 0)
+               return -1;
+
+       ret = git_atomic32_get(&init_count);
+
+       if (init_unlock() < 0)
+               return -1;
+
+       return ret;
+}
+
+int git_runtime_shutdown(void)
+{
+       int ret;
+
+       /* Enter the lock */
+       if (init_lock() < 0)
+               return -1;
+
+       /* Only do work on a 1 -> 0 transition of the refcount */
+       if ((ret = git_atomic32_dec(&init_count)) == 0)
+               shutdown_common();
+
+       /* Exit the lock */
+       if (init_unlock() < 0)
+               return -1;
+
+       return ret;
+}
diff --git a/src/runtime.h b/src/runtime.h
new file mode 100644 (file)
index 0000000..24ac58e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_runtime_h__
+#define INCLUDE_runtime_h__
+
+#include "common.h"
+
+typedef int (*git_runtime_init_fn)(void);
+typedef void (*git_runtime_shutdown_fn)(void);
+
+/**
+ * Start up a new runtime.  If this is the first time that this
+ * function is called within the context of the current library
+ * or executable, then the given `init_fns` will be invoked.  If
+ * it is not the first time, they will be ignored.
+ *
+ * The given initialization functions _may_ register shutdown
+ * handlers using `git_runtime_shutdown_register` to be notified
+ * when the runtime is shutdown.
+ *
+ * @param init_fns The list of initialization functions to call
+ * @param cnt The number of init_fns
+ * @return The number of initializations performed (including this one) or an error
+ */
+int git_runtime_init(git_runtime_init_fn init_fns[], size_t cnt);
+
+/*
+ * Returns the number of initializations active (the number of calls to
+ * `git_runtime_init` minus the number of calls sto `git_runtime_shutdown`).
+ * If 0, the runtime is not currently initialized.
+ *
+ * @return The number of initializations performed or an error
+ */
+int git_runtime_init_count(void);
+
+/**
+ * Shut down the runtime.  If this is the last shutdown call,
+ * such that there are no remaining `init` calls, then any
+ * shutdown hooks that have been registered will be invoked.
+ *
+ * The number of outstanding initializations will be returned.
+ * If this number is 0, then the runtime is shutdown.
+ *
+ * @return The number of outstanding initializations (after this one) or an error
+ */
+int git_runtime_shutdown(void);
+
+/**
+ * Register a shutdown handler for this runtime.  This should be done
+ * by a function invoked by `git_runtime_init` to ensure that the
+ * appropriate locks are taken.
+ *
+ * @param callback The shutdown handler callback
+ * @return 0 or an error code
+ */
+int git_runtime_shutdown_register(git_runtime_shutdown_fn callback);
+
+#endif
diff --git a/src/settings.c b/src/settings.c
deleted file mode 100644 (file)
index 69ebcb7..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "common.h"
-
-#ifdef GIT_OPENSSL
-# include <openssl/err.h>
-#endif
-
-#ifdef GIT_MBEDTLS
-# include <mbedtls/error.h>
-#endif
-
-#include <git2.h>
-#include "alloc.h"
-#include "sysdir.h"
-#include "cache.h"
-#include "global.h"
-#include "object.h"
-#include "odb.h"
-#include "refs.h"
-#include "index.h"
-#include "transports/smart.h"
-#include "transports/http.h"
-#include "streams/openssl.h"
-#include "streams/mbedtls.h"
-
-int git_libgit2_version(int *major, int *minor, int *rev)
-{
-       *major = LIBGIT2_VER_MAJOR;
-       *minor = LIBGIT2_VER_MINOR;
-       *rev = LIBGIT2_VER_REVISION;
-
-       return 0;
-}
-
-int git_libgit2_features(void)
-{
-       return 0
-#ifdef GIT_THREADS
-               | GIT_FEATURE_THREADS
-#endif
-#ifdef GIT_HTTPS
-               | GIT_FEATURE_HTTPS
-#endif
-#if defined(GIT_SSH)
-               | GIT_FEATURE_SSH
-#endif
-#if defined(GIT_USE_NSEC)
-               | GIT_FEATURE_NSEC
-#endif
-       ;
-}
-
-/* Declarations for tuneable settings */
-extern size_t git_mwindow__window_size;
-extern size_t git_mwindow__mapped_limit;
-extern size_t git_mwindow__file_limit;
-extern size_t git_indexer__max_objects;
-extern bool git_disable_pack_keep_file_checks;
-
-static int config_level_to_sysdir(int config_level)
-{
-       int val = -1;
-
-       switch (config_level) {
-       case GIT_CONFIG_LEVEL_SYSTEM:
-               val = GIT_SYSDIR_SYSTEM;
-               break;
-       case GIT_CONFIG_LEVEL_XDG:
-               val = GIT_SYSDIR_XDG;
-               break;
-       case GIT_CONFIG_LEVEL_GLOBAL:
-               val = GIT_SYSDIR_GLOBAL;
-               break;
-       case GIT_CONFIG_LEVEL_PROGRAMDATA:
-               val = GIT_SYSDIR_PROGRAMDATA;
-               break;
-       default:
-               git_error_set(
-                       GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
-       }
-
-       return val;
-}
-
-extern char *git__user_agent;
-extern char *git__ssl_ciphers;
-
-const char *git_libgit2__user_agent(void)
-{
-       return git__user_agent;
-}
-
-const char *git_libgit2__ssl_ciphers(void)
-{
-       return git__ssl_ciphers;
-}
-
-int git_libgit2_opts(int key, ...)
-{
-       int error = 0;
-       va_list ap;
-
-       va_start(ap, key);
-
-       switch (key) {
-       case GIT_OPT_SET_MWINDOW_SIZE:
-               git_mwindow__window_size = va_arg(ap, size_t);
-               break;
-
-       case GIT_OPT_GET_MWINDOW_SIZE:
-               *(va_arg(ap, size_t *)) = git_mwindow__window_size;
-               break;
-
-       case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
-               git_mwindow__mapped_limit = va_arg(ap, size_t);
-               break;
-
-       case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
-               *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
-               break;
-
-       case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
-               git_mwindow__file_limit = va_arg(ap, size_t);
-               break;
-
-       case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
-               *(va_arg(ap, size_t *)) = git_mwindow__file_limit;
-               break;
-
-       case GIT_OPT_GET_SEARCH_PATH:
-               if ((error = config_level_to_sysdir(va_arg(ap, int))) >= 0) {
-                       git_buf *out = va_arg(ap, git_buf *);
-                       const git_buf *tmp;
-
-                       git_buf_sanitize(out);
-                       if ((error = git_sysdir_get(&tmp, error)) < 0)
-                               break;
-
-                       error = git_buf_sets(out, tmp->ptr);
-               }
-               break;
-
-       case GIT_OPT_SET_SEARCH_PATH:
-               if ((error = config_level_to_sysdir(va_arg(ap, int))) >= 0)
-                       error = git_sysdir_set(error, va_arg(ap, const char *));
-               break;
-
-       case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
-               {
-                       git_object_t type = (git_object_t)va_arg(ap, int);
-                       size_t size = va_arg(ap, size_t);
-                       error = git_cache_set_max_object_size(type, size);
-                       break;
-               }
-
-       case GIT_OPT_SET_CACHE_MAX_SIZE:
-               git_cache__max_storage = va_arg(ap, ssize_t);
-               break;
-
-       case GIT_OPT_ENABLE_CACHING:
-               git_cache__enabled = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_GET_CACHED_MEMORY:
-               *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
-               *(va_arg(ap, ssize_t *)) = git_cache__max_storage;
-               break;
-
-       case GIT_OPT_GET_TEMPLATE_PATH:
-               {
-                       git_buf *out = va_arg(ap, git_buf *);
-                       const git_buf *tmp;
-
-                       git_buf_sanitize(out);
-                       if ((error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0)
-                               break;
-
-                       error = git_buf_sets(out, tmp->ptr);
-               }
-               break;
-
-       case GIT_OPT_SET_TEMPLATE_PATH:
-               error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
-               break;
-
-       case GIT_OPT_SET_SSL_CERT_LOCATIONS:
-#ifdef GIT_OPENSSL
-               {
-                       const char *file = va_arg(ap, const char *);
-                       const char *path = va_arg(ap, const char *);
-                       error = git_openssl__set_cert_location(file, path);
-               }
-#elif defined(GIT_MBEDTLS)
-               {
-                       const char *file = va_arg(ap, const char *);
-                       const char *path = va_arg(ap, const char *);
-                       if (file)
-                               error = git_mbedtls__set_cert_location(file, 0);
-                       if (error && path)
-                               error = git_mbedtls__set_cert_location(path, 1);
-               }
-#else
-               git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
-               error = -1;
-#endif
-               break;
-       case GIT_OPT_SET_USER_AGENT:
-               git__free(git__user_agent);
-               git__user_agent = git__strdup(va_arg(ap, const char *));
-               if (!git__user_agent) {
-                       git_error_set_oom();
-                       error = -1;
-               }
-
-               break;
-
-       case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
-               git_object__strict_input_validation = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
-               git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_SET_SSL_CIPHERS:
-#if (GIT_OPENSSL || GIT_MBEDTLS)
-               {
-                       git__free(git__ssl_ciphers);
-                       git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
-                       if (!git__ssl_ciphers) {
-                               git_error_set_oom();
-                               error = -1;
-                       }
-               }
-#else
-               git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
-               error = -1;
-#endif
-               break;
-
-       case GIT_OPT_GET_USER_AGENT:
-               {
-                       git_buf *out = va_arg(ap, git_buf *);
-                       git_buf_sanitize(out);
-                       error = git_buf_sets(out, git__user_agent);
-               }
-               break;
-
-       case GIT_OPT_ENABLE_OFS_DELTA:
-               git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_ENABLE_FSYNC_GITDIR:
-               git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_GET_WINDOWS_SHAREMODE:
-#ifdef GIT_WIN32
-               *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
-#endif
-               break;
-
-       case GIT_OPT_SET_WINDOWS_SHAREMODE:
-#ifdef GIT_WIN32
-               git_win32__createfile_sharemode = va_arg(ap, unsigned long);
-#endif
-               break;
-
-       case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
-               git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_SET_ALLOCATOR:
-               error = git_allocator_setup(va_arg(ap, git_allocator *));
-               break;
-
-       case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
-               git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_SET_PACK_MAX_OBJECTS:
-               git_indexer__max_objects = va_arg(ap, size_t);
-               break;
-
-       case GIT_OPT_GET_PACK_MAX_OBJECTS:
-               *(va_arg(ap, size_t *)) = git_indexer__max_objects;
-               break;
-
-       case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
-               git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
-               break;
-
-       case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
-               git_http__expect_continue = (va_arg(ap, int) != 0);
-               break;
-
-       default:
-               git_error_set(GIT_ERROR_INVALID, "invalid option key");
-               error = -1;
-       }
-
-       va_end(ap);
-
-       return error;
-}
diff --git a/src/settings.h b/src/settings.h
new file mode 100644 (file)
index 0000000..dc42ce9
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+extern int git_settings_global_init(void);
+
+extern const char *git_libgit2__user_agent(void);
+extern const char *git_libgit2__ssl_ciphers(void);
index f4c8a104aba08680b92c2794a8e006324930c9cf..1efda212a0adcbef76380ea7efc1a33667b25d35 100644 (file)
@@ -65,7 +65,8 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema
 {
        git_signature *p = NULL;
 
-       assert(name && email);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(email);
 
        *sig_out = NULL;
 
@@ -279,7 +280,8 @@ int git_signature_from_buffer(git_signature **out, const char *buf)
        const char *buf_end;
        int error;
 
-       assert(out && buf);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(buf);
 
        *out = NULL;
 
@@ -302,8 +304,6 @@ void git_signature__writebuf(git_buf *buf, const char *header, const git_signatu
        int offset, hours, mins;
        char sign;
 
-       assert(buf && sig);
-
        offset = sig->when.offset;
        sign = (sig->when.offset < 0 || sig->when.sign == '-') ? '-' : '+';
 
@@ -320,7 +320,8 @@ void git_signature__writebuf(git_buf *buf, const char *header, const git_signatu
 
 bool git_signature__equal(const git_signature *one, const git_signature *two)
 {
-       assert(one && two);
+       GIT_ASSERT_ARG(one);
+       GIT_ASSERT_ARG(two);
 
        return
                git__strcmp(one->name, two->name) == 0 &&
index e553d01dd6dc5999facf54360f2e53a23597fa14..0e1f63ceb00f2f516d34d0c6c4cc4969d3ee3a79 100644 (file)
@@ -12,7 +12,7 @@
 #include "util.h"
 #include "futils.h"
 #include "vector.h"
-#include "thread-utils.h"
+#include "thread.h"
 #include "pool.h"
 #include "strmap.h"
 
@@ -58,7 +58,7 @@ typedef struct {
  *        may be NULL.  The cache makes it easy to load this and check
  *        if it has been modified since the last load and/or write.
  */
-int git_sortedcache_new(
+GIT_WARN_UNUSED_RESULT int git_sortedcache_new(
        git_sortedcache **out,
        size_t item_path_offset, /* use offsetof(struct, path-field) macro */
        git_sortedcache_free_item_fn free_item,
@@ -71,7 +71,7 @@ int git_sortedcache_new(
  * - `copy_item` can be NULL to just use memcpy
  * - if `lock`, grabs read lock on `src` during copy and releases after
  */
-int git_sortedcache_copy(
+GIT_WARN_UNUSED_RESULT int git_sortedcache_copy(
        git_sortedcache **out,
        git_sortedcache *src,
        bool lock,
@@ -100,7 +100,7 @@ const char *git_sortedcache_path(git_sortedcache *sc);
  */
 
 /* Lock sortedcache for write */
-int git_sortedcache_wlock(git_sortedcache *sc);
+GIT_WARN_UNUSED_RESULT int git_sortedcache_wlock(git_sortedcache *sc);
 
 /* Unlock sorted cache when done with write */
 void git_sortedcache_wunlock(git_sortedcache *sc);
@@ -120,7 +120,8 @@ void git_sortedcache_wunlock(git_sortedcache *sc);
  *
  * @return 0 if up-to-date, 1 if out-of-date, <0 on error
  */
-int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf);
+GIT_WARN_UNUSED_RESULT int git_sortedcache_lockandload(
+       git_sortedcache *sc, git_buf *buf);
 
 /* Refresh file timestamp after write completes
  * You should already be holding the write lock when you call this.
@@ -132,12 +133,13 @@ void git_sortedcache_updated(git_sortedcache *sc);
  * If `wlock` is true, grabs write lock and releases when done, otherwise
  * you should already be holding a write lock when you call this.
  */
-int git_sortedcache_clear(git_sortedcache *sc, bool wlock);
+GIT_WARN_UNUSED_RESULT int git_sortedcache_clear(
+       git_sortedcache *sc, bool wlock);
 
 /* Find and/or insert item, returning pointer to item data.
  * You should already be holding the write lock when you call this.
  */
-int git_sortedcache_upsert(
+GIT_WARN_UNUSED_RESULT int git_sortedcache_upsert(
        void **out, git_sortedcache *sc, const char *key);
 
 /* Removes entry at pos from cache
@@ -155,7 +157,7 @@ int git_sortedcache_remove(git_sortedcache *sc, size_t pos);
  */
 
 /* Lock sortedcache for read */
-int git_sortedcache_rlock(git_sortedcache *sc);
+GIT_WARN_UNUSED_RESULT int git_sortedcache_rlock(git_sortedcache *sc);
 
 /* Unlock sorted cache when done with read */
 void git_sortedcache_runlock(git_sortedcache *sc);
index 0d5dc4351a45d3162d0e9d5348067616047df743..49ea26fdd529243aa3da6224ab6b641b5ab808d4 100644 (file)
@@ -56,7 +56,7 @@ static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
        return git_buf_oom(out) ? -1 : 0;
 }
 
-static int append_commit_description(git_buf *out, git_commitcommit)
+static int append_commit_description(git_buf *out, git_commit *commit)
 {
        const char *summary = git_commit_summary(commit);
        GIT_ERROR_CHECK_ALLOC(summary);
@@ -546,7 +546,9 @@ int git_stash_save(
        git_buf msg = GIT_BUF_INIT;
        int error;
 
-       assert(out && repo && stasher);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(stasher);
 
        if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
                return error;
index eca1f49120f2bf55ae80d9d04427a8a903f4887c..c98564643fc9bd5eff7380184f2e804b9122be02 100644 (file)
@@ -391,14 +391,14 @@ done:
 
 size_t git_status_list_entrycount(git_status_list *status)
 {
-       assert(status);
+       GIT_ASSERT_ARG_WITH_RETVAL(status, 0);
 
        return status->paired.length;
 }
 
 const git_status_entry *git_status_byindex(git_status_list *status, size_t i)
 {
-       assert(status);
+       GIT_ASSERT_ARG_WITH_RETVAL(status, NULL);
 
        return git_vector_get(&status->paired, i);
 }
@@ -492,7 +492,9 @@ int git_status_file(
        struct status_file_info sfi = {0};
        git_index *index;
 
-       assert(status_flags && repo && path);
+       GIT_ASSERT_ARG(status_flags);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(path);
 
        if ((error = git_repository_index__weakptr(&index, repo)) < 0)
                return error;
@@ -558,7 +560,8 @@ int git_status_init_options(git_status_options *opts, unsigned int version)
 int git_status_list_get_perfdata(
        git_diff_perfdata *out, const git_status_list *status)
 {
-       assert(out);
+       GIT_ASSERT_ARG(out);
+
        GIT_ERROR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
 
        out->stat_calls = 0;
index 54fe9fbfba4f33ff6f51619045dbfbf2ff1d59f1..2f9b77cc2800a10b92b7e2cf780f538530906bde 100644 (file)
@@ -13,7 +13,8 @@ int git_strarray_copy(git_strarray *tgt, const git_strarray *src)
 {
        size_t i;
 
-       assert(tgt && src);
+       GIT_ASSERT_ARG(tgt);
+       GIT_ASSERT_ARG(src);
 
        memset(tgt, 0, sizeof(*tgt));
 
index cbe2f681a938064ee1ac1c588c0110cd9cd00b63..b3a35ab0200a3a7bdabef4aec831e2c78f7545a9 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <ctype.h>
 
-#include "global.h"
+#include "runtime.h"
 #include "stream.h"
 #include "streams/socket.h"
 #include "netops.h"
@@ -68,8 +68,6 @@ static void shutdown_ssl(void)
        }
 }
 
-int git_mbedtls__set_cert_location(const char *path, int is_dir);
-
 int git_mbedtls_stream_global_init(void)
 {
        int loaded = 0;
@@ -148,13 +146,11 @@ int git_mbedtls_stream_global_init(void)
 
        /* load default certificates */
        if (crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
-               loaded = (git_mbedtls__set_cert_location(crtpath, 0) == 0);
+               loaded = (git_mbedtls__set_cert_location(crtpath, NULL) == 0);
        if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
-               loaded = (git_mbedtls__set_cert_location(crtpath, 1) == 0);
-
-       git__on_shutdown(shutdown_ssl);
+               loaded = (git_mbedtls__set_cert_location(NULL, crtpath) == 0);
 
-       return 0;
+       return git_runtime_shutdown_register(shutdown_ssl);
 
 cleanup:
        mbedtls_ctr_drbg_free(ctr_drbg);
@@ -183,8 +179,8 @@ static int ssl_set_error(mbedtls_ssl_context *ssl, int error)
        char errbuf[512];
        int ret = -1;
 
-       assert(error != MBEDTLS_ERR_SSL_WANT_READ);
-       assert(error != MBEDTLS_ERR_SSL_WANT_WRITE);
+       GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_READ);
+       GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_WRITE);
 
        if (error != 0)
                mbedtls_strerror( error, errbuf, 512 );
@@ -425,7 +421,9 @@ int git_mbedtls_stream_new(
        git_stream *stream;
        int error;
 
-       assert(out && host && port);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
+       GIT_ASSERT_ARG(port);
 
        if ((error = git_socket_stream_new(&stream, host, port)) < 0)
                return error;
@@ -438,23 +436,22 @@ int git_mbedtls_stream_new(
        return error;
 }
 
-int git_mbedtls__set_cert_location(const char *path, int is_dir)
+int git_mbedtls__set_cert_location(const char *file, const char *path)
 {
        int ret = 0;
        char errbuf[512];
        mbedtls_x509_crt *cacert;
 
-       assert(path != NULL);
+       GIT_ASSERT_ARG(file || path);
 
        cacert = git__malloc(sizeof(mbedtls_x509_crt));
        GIT_ERROR_CHECK_ALLOC(cacert);
 
        mbedtls_x509_crt_init(cacert);
-       if (is_dir) {
+       if (file)
+               ret = mbedtls_x509_crt_parse_file(cacert, file);
+       if (ret >= 0 && path)
                ret = mbedtls_x509_crt_parse_path(cacert, path);
-       } else {
-               ret = mbedtls_x509_crt_parse_file(cacert, path);
-       }
        /* mbedtls_x509_crt_parse_path returns the number of invalid certs on success */
        if (ret < 0) {
                mbedtls_x509_crt_free(cacert);
index 7de94b9fbccaba59a21bc6f13eddb8eb17759516..bcca6dd401ab8b34d564f37964972d8fa59cba07 100644 (file)
@@ -14,7 +14,7 @@
 extern int git_mbedtls_stream_global_init(void);
 
 #ifdef GIT_MBEDTLS
-extern int git_mbedtls__set_cert_location(const char *path, int is_dir);
+extern int git_mbedtls__set_cert_location(const char *file, const char *path);
 
 extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
 extern int git_mbedtls_stream_wrap(git_stream **out, git_stream *in, const char *host);
index 6a490d17d2e787bf200081dda865283fe77dffa6..89c96780c145471f243db368fd7765d187996990 100644 (file)
@@ -6,12 +6,16 @@
  */
 
 #include "streams/openssl.h"
+#include "streams/openssl_legacy.h"
+#include "streams/openssl_dynamic.h"
 
 #ifdef GIT_OPENSSL
 
 #include <ctype.h>
 
-#include "global.h"
+#include "common.h"
+#include "runtime.h"
+#include "settings.h"
 #include "posix.h"
 #include "stream.h"
 #include "streams/socket.h"
 # include <netinet/in.h>
 #endif
 
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
-#include <openssl/bio.h>
+#ifndef GIT_OPENSSL_DYNAMIC
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509v3.h>
+# include <openssl/bio.h>
+#endif
 
 SSL_CTX *git__ssl_ctx;
 
 #define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
 
-#if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \
-     (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
-# define OPENSSL_LEGACY_API
-#endif
-
-/*
- * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
- * which do not exist in previous versions. We define these inline functions so
- * we can program against the interface instead of littering the implementation
- * with ifdefs. We do the same for OPENSSL_init_ssl.
- */
-#if defined(OPENSSL_LEGACY_API)
-static int OPENSSL_init_ssl(int opts, void *settings)
-{
-       GIT_UNUSED(opts);
-       GIT_UNUSED(settings);
-       SSL_load_error_strings();
-       OpenSSL_add_ssl_algorithms();
-       return 0;
-}
-
-static BIO_METHOD* BIO_meth_new(int type, const char *name)
-{
-       BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
-       if (!meth) {
-               return NULL;
-       }
-
-       meth->type = type;
-       meth->name = name;
-
-       return meth;
-}
-
-static void BIO_meth_free(BIO_METHOD *biom)
-{
-       git__free(biom);
-}
-
-static int BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
-{
-       biom->bwrite = write;
-       return 1;
-}
-
-static int BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
-{
-       biom->bread = read;
-       return 1;
-}
-
-static int BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
-{
-       biom->bputs = puts;
-       return 1;
-}
-
-static int BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
-
-{
-       biom->bgets = gets;
-       return 1;
-}
-
-static int BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
-{
-       biom->ctrl = ctrl;
-       return 1;
-}
-
-static int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
-{
-       biom->create = create;
-       return 1;
-}
-
-static int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
-{
-       biom->destroy = destroy;
-       return 1;
-}
-
-static int BIO_get_new_index(void)
-{
-       /* This exists as of 1.1 so before we'd just have 0 */
-       return 0;
-}
-
-static void BIO_set_init(BIO *b, int init)
-{
-       b->init = init;
-}
-
-static void BIO_set_data(BIO *a, void *ptr)
-{
-       a->ptr = ptr;
-}
-
-static void *BIO_get_data(BIO *a)
-{
-       return a->ptr;
-}
-
-static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
-{
-       return ASN1_STRING_data((ASN1_STRING *)x);
-}
-
-# if defined(GIT_THREADS)
-static git_mutex *openssl_locks;
-
-static void openssl_locking_function(
-       int mode, int n, const char *file, int line)
-{
-       int lock;
-
-       GIT_UNUSED(file);
-       GIT_UNUSED(line);
-
-       lock = mode & CRYPTO_LOCK;
-
-       if (lock) {
-               (void)git_mutex_lock(&openssl_locks[n]);
-       } else {
-               git_mutex_unlock(&openssl_locks[n]);
-       }
-}
-
-static void shutdown_ssl_locking(void)
-{
-       int num_locks, i;
-
-       num_locks = CRYPTO_num_locks();
-       CRYPTO_set_locking_callback(NULL);
-
-       for (i = 0; i < num_locks; ++i)
-               git_mutex_free(&openssl_locks[i]);
-       git__free(openssl_locks);
-}
-# endif /* GIT_THREADS */
-#endif /* OPENSSL_LEGACY_API */
 
 static BIO_METHOD *git_stream_bio_method;
 static int init_bio_method(void);
@@ -197,46 +62,47 @@ static void shutdown_ssl(void)
 }
 
 #ifdef VALGRIND
-#ifdef OPENSSL_LEGACY_API
-static void *git_openssl_malloc(size_t bytes)
-{
-       return git__calloc(1, bytes);
-}
+# if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
 
-static void *git_openssl_realloc(void *mem, size_t size)
-{
-       return git__realloc(mem, size);
-}
-
-static void git_openssl_free(void *mem)
-{
-       return git__free(mem);
-}
-#else
 static void *git_openssl_malloc(size_t bytes, const char *file, int line)
 {
        GIT_UNUSED(file);
        GIT_UNUSED(line);
        return git__calloc(1, bytes);
 }
-
 static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line)
 {
        GIT_UNUSED(file);
        GIT_UNUSED(line);
        return git__realloc(mem, size);
 }
-
 static void git_openssl_free(void *mem, const char *file, int line)
 {
        GIT_UNUSED(file);
        GIT_UNUSED(line);
-       return git__free(mem);
+       git__free(mem);
+}
+# else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */
+static void *git_openssl_malloc(size_t bytes)
+{
+       return git__calloc(1, bytes);
 }
-#endif
-#endif
 
-int git_openssl_stream_global_init(void)
+static void *git_openssl_realloc(void *mem, size_t size)
+{
+       return git__realloc(mem, size);
+}
+
+static void git_openssl_free(void *mem)
+{
+       git__free(mem);
+}
+# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */
+#endif /* VALGRIND */
+
+static int openssl_init(void)
 {
        long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
        const char *ciphers = git_libgit2__ssl_ciphers();
@@ -250,13 +116,18 @@ int git_openssl_stream_global_init(void)
 #endif
 
 #ifdef VALGRIND
-       /* Swap in our own allocator functions that initialize allocated memory */
-       if (!allocators_initialized &&
+       /*
+        * Swap in our own allocator functions that initialize
+        * allocated memory to avoid spurious valgrind warnings.
+        * Don't error on failure; many builds of OpenSSL do not
+        * allow you to set these functions.
+        */
+       if (!allocators_initialized) {
            CRYPTO_set_mem_functions(git_openssl_malloc,
                                     git_openssl_realloc,
-                                    git_openssl_free) != 1)
-               goto error;
-       allocators_initialized = true;
+                                    git_openssl_free);
+               allocators_initialized = true;
+       }
 #endif
 
        OPENSSL_init_ssl(0, NULL);
@@ -285,9 +156,7 @@ int git_openssl_stream_global_init(void)
        if (init_bio_method() < 0)
                goto error;
 
-       git__on_shutdown(shutdown_ssl);
-
-       return 0;
+       return git_runtime_shutdown_register(shutdown_ssl);
 
 error:
        git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
@@ -297,42 +166,60 @@ error:
        return -1;
 }
 
-#if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API)
-static void threadid_cb(CRYPTO_THREADID *threadid)
+/*
+ * When we use dynamic loading, we defer OpenSSL initialization until
+ * it's first used.  `openssl_ensure_initialized` will do the work
+ * under a mutex.
+ */
+git_mutex openssl_mutex;
+bool openssl_initialized;
+
+int git_openssl_stream_global_init(void)
 {
-       GIT_UNUSED(threadid);
-       CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
-}
+#ifndef GIT_OPENSSL_DYNAMIC
+       return openssl_init();
+#else
+       if (git_mutex_init(&openssl_mutex) != 0)
+               return -1;
+
+       return 0;
 #endif
+}
 
-int git_openssl_set_locking(void)
+static int openssl_ensure_initialized(void)
 {
-#if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API)
-       int num_locks, i;
+#ifdef GIT_OPENSSL_DYNAMIC
+       int error = 0;
 
-       CRYPTO_THREADID_set_callback(threadid_cb);
+       if (git_mutex_lock(&openssl_mutex) != 0)
+               return -1;
 
-       num_locks = CRYPTO_num_locks();
-       openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
-       GIT_ERROR_CHECK_ALLOC(openssl_locks);
+       if (!openssl_initialized) {
+               if ((error = git_openssl_stream_dynamic_init()) == 0)
+                       error = openssl_init();
 
-       for (i = 0; i < num_locks; i++) {
-               if (git_mutex_init(&openssl_locks[i]) != 0) {
-                       git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks");
-                       return -1;
-               }
+               openssl_initialized = true;
        }
 
-       CRYPTO_set_locking_callback(openssl_locking_function);
-       git__on_shutdown(shutdown_ssl_locking);
+       error |= git_mutex_unlock(&openssl_mutex);
+       return error;
+
+#else
        return 0;
-#elif !defined(OPENSSL_LEGACY_API)
+#endif
+}
+
+#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
+int git_openssl_set_locking(void)
+{
+# ifdef GIT_THREADS
        return 0;
-#else
+# else
        git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads");
        return -1;
-#endif
+# endif
 }
+#endif
 
 
 static int bio_create(BIO *b)
@@ -415,8 +302,8 @@ static int ssl_set_error(SSL *ssl, int error)
 
        err = SSL_get_error(ssl, error);
 
-       assert(err != SSL_ERROR_WANT_READ);
-       assert(err != SSL_ERROR_WANT_WRITE);
+       GIT_ASSERT(err != SSL_ERROR_WANT_READ);
+       GIT_ASSERT(err != SSL_ERROR_WANT_WRITE);
 
        switch (err) {
        case SSL_ERROR_WANT_CONNECT:
@@ -758,7 +645,9 @@ static int openssl_stream_wrap(
 {
        openssl_stream *st;
 
-       assert(out && in && host);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(in);
+       GIT_ASSERT_ARG(host);
 
        st = git__calloc(1, sizeof(openssl_stream));
        GIT_ERROR_CHECK_ALLOC(st);
@@ -793,6 +682,9 @@ static int openssl_stream_wrap(
 
 int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
 {
+       if (openssl_ensure_initialized() < 0)
+               return -1;
+
        return openssl_stream_wrap(out, in, host, 0);
 }
 
@@ -801,7 +693,12 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
        git_stream *stream = NULL;
        int error;
 
-       assert(out && host && port);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
+       GIT_ASSERT_ARG(port);
+
+       if (openssl_ensure_initialized() < 0)
+               return -1;
 
        if ((error = git_socket_stream_new(&stream, host, port)) < 0)
                return error;
@@ -816,6 +713,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
 
 int git_openssl__set_cert_location(const char *file, const char *path)
 {
+       if (openssl_ensure_initialized() < 0)
+               return -1;
+
        if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
                char errmsg[256];
 
index 826d1efbc7773b043b1c40e4f2c0ec6d4794d74f..89fb60a82eec8a4f04de3b7b73b258670f8e84bb 100644 (file)
@@ -8,14 +8,22 @@
 #define INCLUDE_streams_openssl_h__
 
 #include "common.h"
+#include "streams/openssl_legacy.h"
+#include "streams/openssl_dynamic.h"
 
 #include "git2/sys/stream.h"
 
 extern int git_openssl_stream_global_init(void);
 
+#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC)
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509v3.h>
+# include <openssl/bio.h>
+# endif
+
 #ifdef GIT_OPENSSL
 extern int git_openssl__set_cert_location(const char *file, const char *path);
-
 extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
 extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host);
 #endif
diff --git a/src/streams/openssl_dynamic.c b/src/streams/openssl_dynamic.c
new file mode 100644 (file)
index 0000000..da16b6e
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "streams/openssl.h"
+#include "streams/openssl_dynamic.h"
+
+#if defined(GIT_OPENSSL) && defined(GIT_OPENSSL_DYNAMIC)
+
+#include "runtime.h"
+
+#include <dlfcn.h>
+
+unsigned char *(*ASN1_STRING_data)(ASN1_STRING *x);
+const unsigned char *(*ASN1_STRING_get0_data)(const ASN1_STRING *x);
+int (*ASN1_STRING_length)(const ASN1_STRING *x);
+int (*ASN1_STRING_to_UTF8)(unsigned char **out, const ASN1_STRING *in);
+int (*ASN1_STRING_type)(const ASN1_STRING *x);
+
+void *(*BIO_get_data)(BIO *a);
+int (*BIO_get_new_index)(void);
+int (*OPENSSL_init_ssl)(uint64_t opts, const void *settings);
+void (*BIO_meth_free)(BIO_METHOD *biom);
+int (*BIO_meth_set_create)(BIO_METHOD *biom, int (*create) (BIO *));
+int (*BIO_meth_set_ctrl)(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *));
+int (*BIO_meth_set_destroy)(BIO_METHOD *biom, int (*destroy) (BIO *));
+int (*BIO_meth_set_gets)(BIO_METHOD *biom, int (*gets) (BIO *, char *, int));
+int (*BIO_meth_set_puts)(BIO_METHOD *biom, int (*puts) (BIO *, const char *));
+int (*BIO_meth_set_read)(BIO_METHOD *biom, int (*read) (BIO *, char *, int));
+int (*BIO_meth_set_write)(BIO_METHOD *biom, int (*write) (BIO *, const char *, int));
+BIO_METHOD *(*BIO_meth_new)(int type, const char *name);
+BIO *(*BIO_new)(const BIO_METHOD *type);
+void (*BIO_set_data)(BIO *a, void *ptr);
+void (*BIO_set_init)(BIO *a, int init);
+
+void (*CRYPTO_free)(void *ptr, const char *file, int line);
+void *(*CRYPTO_malloc)(size_t num, const char *file, int line);
+int (*CRYPTO_num_locks)(void);
+void (*CRYPTO_set_locking_callback)(void (*func)(int mode, int type, const char *file, int line));
+int (*CRYPTO_set_mem_functions)(void *(*m)(size_t bytes), void *(*r)(void *mem, size_t size), void (*f)(void *mem));
+int (*CRYPTO_THREADID_set_callback)(void (*func)(CRYPTO_THREADID *id));
+void (*CRYPTO_THREADID_set_numeric)(CRYPTO_THREADID *id, unsigned long val);
+
+char *(*ERR_error_string)(unsigned long e, char *buf);
+void (*ERR_error_string_n)(unsigned long e, char *buf, size_t len);
+unsigned long (*ERR_get_error)(void);
+
+int (*SSL_connect)(SSL *ssl);
+long (*SSL_ctrl)(SSL *ssl, int cmd, long arg, void *parg);
+void (*SSL_free)(SSL *ssl);
+int (*SSL_get_error)(SSL *ssl, int ret);
+X509 *(*SSL_get_peer_certificate)(const SSL *ssl);
+long (*SSL_get_verify_result)(const SSL *ssl);
+int (*SSL_library_init)(void);
+void (*SSL_load_error_strings)(void);
+SSL *(*SSL_new)(SSL_CTX *ctx);
+int (*SSL_read)(SSL *ssl, const void *buf, int num);
+void (*SSL_set_bio)(SSL *ssl, BIO *rbio, BIO *wbio);
+int (*SSL_shutdown)(SSL *ssl);
+int (*SSL_write)(SSL *ssl, const void *buf, int num);
+
+long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg);
+void (*SSL_CTX_free)(SSL_CTX *ctx);
+SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method);
+int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
+int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx);
+long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options);
+void (*SSL_CTX_set_verify)(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *));
+int (*SSL_CTX_load_verify_locations)(SSL_CTX *ctx, const char *CAfile, const char *CApath);
+
+const SSL_METHOD *(*SSLv23_method)(void);
+const SSL_METHOD *(*TLS_method)(void);
+
+ASN1_STRING *(*X509_NAME_ENTRY_get_data)(const X509_NAME_ENTRY *ne);
+X509_NAME_ENTRY *(*X509_NAME_get_entry)(X509_NAME *name, int loc);
+int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos);
+void (*X509_free)(X509 *a);
+void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx);
+X509_NAME *(*X509_get_subject_name)(const X509 *x);
+
+int (*i2d_X509)(X509 *a, unsigned char **ppout);
+
+int (*OPENSSL_sk_num)(const void *sk);
+void *(*OPENSSL_sk_value)(const void *sk, int i);
+void (*OPENSSL_sk_free)(void *sk);
+
+int (*sk_num)(const void *sk);
+void *(*sk_value)(const void *sk, int i);
+void (*sk_free)(void *sk);
+
+void *openssl_handle;
+
+GIT_INLINE(void *) openssl_sym(int *err, const char *name, bool required)
+{
+       void *symbol;
+
+       /* if we've seen an err, noop to retain it */
+       if (*err)
+               return NULL;
+
+
+       if ((symbol = dlsym(openssl_handle, name)) == NULL && required) {
+               const char *msg = dlerror();
+               git_error_set(GIT_ERROR_SSL, "could not load ssl function '%s': %s", name, msg ? msg : "unknown error");
+               *err = -1;
+       }
+
+       return symbol;
+}
+
+static void dynamic_shutdown(void)
+{
+       dlclose(openssl_handle);
+       openssl_handle = NULL;
+}
+
+int git_openssl_stream_dynamic_init(void)
+{
+       int err = 0;
+
+       if ((openssl_handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL &&
+           (openssl_handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL &&
+           (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL &&
+           (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL &&
+           (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) {
+               git_error_set(GIT_ERROR_SSL, "could not load ssl libraries");
+               return -1;
+       }
+
+       ASN1_STRING_data = (unsigned char *(*)(ASN1_STRING *x))openssl_sym(&err, "ASN1_STRING_data", false);
+       ASN1_STRING_get0_data = (const unsigned char *(*)(const ASN1_STRING *x))openssl_sym(&err, "ASN1_STRING_get0_data", false);
+       ASN1_STRING_length = (int (*)(const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_length", true);
+       ASN1_STRING_to_UTF8 = (int (*)(unsigned char **, const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_to_UTF8", true);
+       ASN1_STRING_type = (int (*)(const ASN1_STRING *))openssl_sym(&err, "ASN1_STRING_type", true);
+
+       BIO_get_data = (void *(*)(BIO *))openssl_sym(&err, "BIO_get_data", false);
+       BIO_get_new_index = (int (*)(void))openssl_sym(&err, "BIO_get_new_index", false);
+       BIO_meth_free = (void (*)(BIO_METHOD *))openssl_sym(&err, "BIO_meth_free", false);
+       BIO_meth_new = (BIO_METHOD *(*)(int, const char *))openssl_sym(&err, "BIO_meth_new", false);
+       BIO_meth_set_create = (int (*)(BIO_METHOD *, int (*)(BIO *)))openssl_sym(&err, "BIO_meth_set_create", false);
+       BIO_meth_set_ctrl = (int (*)(BIO_METHOD *, long (*)(BIO *, int, long, void *)))openssl_sym(&err, "BIO_meth_set_ctrl", false);
+       BIO_meth_set_destroy = (int (*)(BIO_METHOD *, int (*)(BIO *)))openssl_sym(&err, "BIO_meth_set_destroy", false);
+       BIO_meth_set_gets = (int (*)(BIO_METHOD *, int (*)(BIO *, char *, int)))openssl_sym(&err, "BIO_meth_set_gets", false);
+       BIO_meth_set_puts = (int (*)(BIO_METHOD *, int (*)(BIO *, const char *)))openssl_sym(&err, "BIO_meth_set_puts", false);
+       BIO_meth_set_read = (int (*)(BIO_METHOD *, int (*)(BIO *, char *, int)))openssl_sym(&err, "BIO_meth_set_read", false);
+       BIO_meth_set_write = (int (*)(BIO_METHOD *, int (*)(BIO *, const char *, int)))openssl_sym(&err, "BIO_meth_set_write", false);
+       BIO_new = (BIO *(*)(const BIO_METHOD *))openssl_sym(&err, "BIO_new", true);
+       BIO_set_data = (void (*)(BIO *a, void *))openssl_sym(&err, "BIO_set_data", false);
+       BIO_set_init = (void (*)(BIO *a, int))openssl_sym(&err, "BIO_set_init", false);
+
+       CRYPTO_free = (void (*)(void *, const char *, int))openssl_sym(&err, "CRYPTO_free", true);
+       CRYPTO_malloc = (void *(*)(size_t, const char *, int))openssl_sym(&err, "CRYPTO_malloc", true);
+       CRYPTO_num_locks = (int (*)(void))openssl_sym(&err, "CRYPTO_num_locks", false);
+       CRYPTO_set_locking_callback = (void (*)(void (*)(int, int, const char *, int)))openssl_sym(&err, "CRYPTO_set_locking_callback", false);
+       CRYPTO_set_mem_functions = (int (*)(void *(*)(size_t), void *(*)(void *, size_t), void (*f)(void *)))openssl_sym(&err, "CRYPTO_set_mem_functions", true);
+
+       CRYPTO_THREADID_set_callback = (int (*)(void (*)(CRYPTO_THREADID *)))openssl_sym(&err, "CRYPTO_THREADID_set_callback", false);
+       CRYPTO_THREADID_set_numeric = (void (*)(CRYPTO_THREADID *, unsigned long))openssl_sym(&err, "CRYPTO_THREADID_set_numeric", false);
+
+       ERR_error_string = (char *(*)(unsigned long, char *))openssl_sym(&err, "ERR_error_string", true);
+       ERR_error_string_n = (void (*)(unsigned long, char *, size_t))openssl_sym(&err, "ERR_error_string_n", true);
+       ERR_get_error = (unsigned long (*)(void))openssl_sym(&err, "ERR_get_error", true);
+
+       OPENSSL_init_ssl = (int (*)(uint64_t opts, const void *settings))openssl_sym(&err, "OPENSSL_init_ssl", false);
+       OPENSSL_sk_num = (int (*)(const void *))openssl_sym(&err, "OPENSSL_sk_num", false);
+       OPENSSL_sk_value = (void *(*)(const void *sk, int i))openssl_sym(&err, "OPENSSL_sk_value", false);
+       OPENSSL_sk_free = (void (*)(void *))openssl_sym(&err, "OPENSSL_sk_free", false);
+
+       sk_num = (int (*)(const void *))openssl_sym(&err, "sk_num", false);
+       sk_value = (void *(*)(const void *sk, int i))openssl_sym(&err, "sk_value", false);
+       sk_free = (void (*)(void *))openssl_sym(&err, "sk_free", false);
+
+       SSL_connect = (int (*)(SSL *))openssl_sym(&err, "SSL_connect", true);
+       SSL_ctrl = (long (*)(SSL *, int, long, void *))openssl_sym(&err, "SSL_ctrl", true);
+       SSL_get_peer_certificate = (X509 *(*)(const SSL *))openssl_sym(&err, "SSL_get_peer_certificate", true);
+       SSL_library_init = (int (*)(void))openssl_sym(&err, "SSL_library_init", false);
+       SSL_free = (void (*)(SSL *))openssl_sym(&err, "SSL_free", true);
+       SSL_get_error = (int (*)(SSL *, int))openssl_sym(&err, "SSL_get_error", true);
+       SSL_get_verify_result = (long (*)(const SSL *ssl))openssl_sym(&err, "SSL_get_verify_result", true);
+       SSL_load_error_strings = (void (*)(void))openssl_sym(&err, "SSL_load_error_strings", false);
+       SSL_new = (SSL *(*)(SSL_CTX *))openssl_sym(&err, "SSL_new", true);
+       SSL_read = (int (*)(SSL *, const void *, int))openssl_sym(&err, "SSL_read", true);
+       SSL_set_bio = (void (*)(SSL *, BIO *, BIO *))openssl_sym(&err, "SSL_set_bio", true);
+       SSL_shutdown = (int (*)(SSL *ssl))openssl_sym(&err, "SSL_shutdown", true);
+       SSL_write = (int (*)(SSL *, const void *, int))openssl_sym(&err, "SSL_write", true);
+
+       SSL_CTX_ctrl = (long (*)(SSL_CTX *, int, long, void *))openssl_sym(&err, "SSL_CTX_ctrl", true);
+       SSL_CTX_free = (void (*)(SSL_CTX *))openssl_sym(&err, "SSL_CTX_free", true);
+       SSL_CTX_new = (SSL_CTX *(*)(const SSL_METHOD *))openssl_sym(&err, "SSL_CTX_new", true);
+       SSL_CTX_set_cipher_list = (int (*)(SSL_CTX *, const char *))openssl_sym(&err, "SSL_CTX_set_cipher_list", true);
+       SSL_CTX_set_default_verify_paths = (int (*)(SSL_CTX *ctx))openssl_sym(&err, "SSL_CTX_set_default_verify_paths", true);
+       SSL_CTX_set_options = (long (*)(SSL_CTX *, long))openssl_sym(&err, "SSL_CTX_set_options", false);
+       SSL_CTX_set_verify = (void (*)(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *)))openssl_sym(&err, "SSL_CTX_set_verify", true);
+       SSL_CTX_load_verify_locations = (int (*)(SSL_CTX *, const char *, const char *))openssl_sym(&err, "SSL_CTX_load_verify_locations", true);
+
+       SSLv23_method = (const SSL_METHOD *(*)(void))openssl_sym(&err, "SSLv23_method", false);
+       TLS_method = (const SSL_METHOD *(*)(void))openssl_sym(&err, "TLS_method", false);
+
+       X509_NAME_ENTRY_get_data = (ASN1_STRING *(*)(const X509_NAME_ENTRY *))openssl_sym(&err, "X509_NAME_ENTRY_get_data", true);
+       X509_NAME_get_entry = (X509_NAME_ENTRY *(*)(X509_NAME *, int))openssl_sym(&err, "X509_NAME_get_entry", true);
+       X509_NAME_get_index_by_NID = (int (*)(X509_NAME *, int, int))openssl_sym(&err, "X509_NAME_get_index_by_NID", true);
+       X509_free = (void (*)(X509 *))openssl_sym(&err, "X509_free", true);
+       X509_get_ext_d2i = (void *(*)(const X509 *x, int nid, int *crit, int *idx))openssl_sym(&err, "X509_get_ext_d2i", true);
+       X509_get_subject_name = (X509_NAME *(*)(const X509 *))openssl_sym(&err, "X509_get_subject_name", true);
+
+       i2d_X509 = (int (*)(X509 *a, unsigned char **ppout))openssl_sym(&err, "i2d_X509", true);
+
+       if (err)
+               goto on_error;
+
+       /* Add legacy functionality */
+       if (!OPENSSL_init_ssl) {
+               OPENSSL_init_ssl = OPENSSL_init_ssl__legacy;
+
+               if (!SSL_library_init ||
+                   !SSL_load_error_strings ||
+                   !CRYPTO_num_locks ||
+                   !CRYPTO_set_locking_callback ||
+                   !CRYPTO_THREADID_set_callback ||
+                   !CRYPTO_THREADID_set_numeric) {
+                       git_error_set(GIT_ERROR_SSL, "could not load legacy openssl initialization functions");
+                       goto on_error;
+               }
+       }
+
+       if (!SSL_CTX_set_options)
+               SSL_CTX_set_options = SSL_CTX_set_options__legacy;
+
+       if (TLS_method)
+               SSLv23_method = TLS_method;
+
+       if (!BIO_meth_new) {
+               BIO_meth_new = BIO_meth_new__legacy;
+               BIO_meth_new = BIO_meth_new__legacy;
+               BIO_meth_free = BIO_meth_free__legacy;
+               BIO_meth_set_write = BIO_meth_set_write__legacy;
+               BIO_meth_set_read = BIO_meth_set_read__legacy;
+               BIO_meth_set_puts = BIO_meth_set_puts__legacy;
+               BIO_meth_set_gets = BIO_meth_set_gets__legacy;
+               BIO_meth_set_ctrl = BIO_meth_set_ctrl__legacy;
+               BIO_meth_set_create = BIO_meth_set_create__legacy;
+               BIO_meth_set_destroy = BIO_meth_set_destroy__legacy;
+               BIO_get_new_index = BIO_get_new_index__legacy;
+               BIO_set_data = BIO_set_data__legacy;
+               BIO_set_init = BIO_set_init__legacy;
+               BIO_get_data = BIO_get_data__legacy;
+       }
+
+       if (!ASN1_STRING_get0_data) {
+               if (!ASN1_STRING_data) {
+                       git_error_set(GIT_ERROR_SSL, "could not load legacy openssl string function");
+                       goto on_error;
+               }
+
+               ASN1_STRING_get0_data = ASN1_STRING_get0_data__legacy;
+       }
+
+       if ((!OPENSSL_sk_num && !sk_num) ||
+           (!OPENSSL_sk_value && !sk_value) ||
+           (!OPENSSL_sk_free && !sk_free)) {
+               git_error_set(GIT_ERROR_SSL, "could not load legacy openssl stack functions");
+               goto on_error;
+       }
+
+       if (git_runtime_shutdown_register(dynamic_shutdown) != 0)
+               goto on_error;
+
+       return 0;
+
+on_error:
+       dlclose(openssl_handle);
+       return -1;
+}
+
+
+int sk_GENERAL_NAME_num(const GENERAL_NAME *sk)
+{
+       if (OPENSSL_sk_num)
+               return OPENSSL_sk_num(sk);
+       else if (sk_num)
+               return sk_num(sk);
+
+       GIT_ASSERT_WITH_RETVAL(false, 0);
+       return 0;
+}
+
+GENERAL_NAME *sk_GENERAL_NAME_value(const GENERAL_NAME *sk, int i)
+{
+       if (OPENSSL_sk_value)
+               return OPENSSL_sk_value(sk, i);
+       else if (sk_value)
+               return sk_value(sk, i);
+
+       GIT_ASSERT_WITH_RETVAL(false, NULL);
+       return NULL;
+}
+
+void GENERAL_NAMES_free(GENERAL_NAME *sk)
+{
+       if (OPENSSL_sk_free)
+               OPENSSL_sk_free(sk);
+       else if (sk_free)
+               sk_free(sk);
+}
+
+#endif /* GIT_OPENSSL && GIT_OPENSSL_DYNAMIC */
diff --git a/src/streams/openssl_dynamic.h b/src/streams/openssl_dynamic.h
new file mode 100644 (file)
index 0000000..12d927a
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#ifndef INCLUDE_streams_openssl_dynamic_h__
+#define INCLUDE_streams_openssl_dynamic_h__
+
+#ifdef GIT_OPENSSL_DYNAMIC
+
+# define BIO_CTRL_FLUSH               11
+
+# define BIO_TYPE_SOURCE_SINK         0x0400
+
+# define CRYPTO_LOCK                  1
+
+# define GEN_DNS                      2
+# define GEN_IPADD                    7
+
+# define NID_commonName               13
+# define NID_subject_alt_name         85
+
+# define SSL_VERIFY_NONE              0x00
+
+# define SSL_CTRL_OPTIONS             32
+# define SSL_CTRL_MODE                33
+# define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
+
+# define SSL_ERROR_NONE               0
+# define SSL_ERROR_SSL                1
+# define SSL_ERROR_WANT_READ          2
+# define SSL_ERROR_WANT_WRITE         3
+# define SSL_ERROR_WANT_X509_LOOKUP   4
+# define SSL_ERROR_SYSCALL            5
+# define SSL_ERROR_ZERO_RETURN        6
+# define SSL_ERROR_WANT_CONNECT       7
+# define SSL_ERROR_WANT_ACCEPT        8
+
+# define SSL_OP_NO_COMPRESSION        0x00020000L
+# define SSL_OP_NO_SSLv2              0x01000000L
+# define SSL_OP_NO_SSLv3              0x02000000L
+
+# define SSL_MODE_AUTO_RETRY          0x00000004L
+
+# define TLSEXT_NAMETYPE_host_name    0
+
+# define V_ASN1_UTF8STRING            12
+
+# define X509_V_OK 0
+
+/* Most of the OpenSSL types are mercifully opaque, so we can treat them like `void *` */
+typedef struct bio_st BIO;
+typedef struct bio_method_st BIO_METHOD;
+typedef void bio_info_cb;
+typedef void * CRYPTO_EX_DATA;
+typedef void CRYPTO_THREADID;
+typedef void GENERAL_NAMES;
+typedef void SSL;
+typedef void SSL_CTX;
+typedef void SSL_METHOD;
+typedef void X509;
+typedef void X509_NAME;
+typedef void X509_NAME_ENTRY;
+typedef void X509_STORE_CTX;
+
+typedef struct {
+    int length;
+    int type;
+    unsigned char *data;
+    long flags;
+} ASN1_STRING;
+
+typedef struct {
+    int type;
+    union {
+        char *ptr;
+        ASN1_STRING *ia5;
+    } d;
+} GENERAL_NAME;
+
+struct bio_st {
+    BIO_METHOD *method;
+    /* bio, mode, argp, argi, argl, ret */
+    long (*callback) (struct bio_st *, int, const char *, int, long, long);
+    char *cb_arg;               /* first argument for the callback */
+    int init;
+    int shutdown;
+    int flags;                  /* extra storage */
+    int retry_reason;
+    int num;
+    void *ptr;
+    struct bio_st *next_bio;    /* used by filter BIOs */
+    struct bio_st *prev_bio;    /* used by filter BIOs */
+    int references;
+    unsigned long num_read;
+    unsigned long num_write;
+    CRYPTO_EX_DATA ex_data;
+};
+
+struct bio_method_st {
+    int type;
+    const char *name;
+    int (*bwrite) (BIO *, const char *, int);
+    int (*bread) (BIO *, char *, int);
+    int (*bputs) (BIO *, const char *);
+    int (*bgets) (BIO *, char *, int);
+    long (*ctrl) (BIO *, int, long, void *);
+    int (*create) (BIO *);
+    int (*destroy) (BIO *);
+    long (*callback_ctrl) (BIO *, int, bio_info_cb *);
+};
+
+extern unsigned char *(*ASN1_STRING_data)(ASN1_STRING *x);
+extern const unsigned char *(*ASN1_STRING_get0_data)(const ASN1_STRING *x);
+extern int (*ASN1_STRING_length)(const ASN1_STRING *x);
+extern int (*ASN1_STRING_to_UTF8)(unsigned char **out, const ASN1_STRING *in);
+extern int (*ASN1_STRING_type)(const ASN1_STRING *x);
+
+extern void *(*BIO_get_data)(BIO *a);
+extern int (*BIO_get_new_index)(void);
+extern int (*OPENSSL_init_ssl)(uint64_t opts, const void *settings);
+extern void (*BIO_meth_free)(BIO_METHOD *biom);
+extern int (*BIO_meth_set_create)(BIO_METHOD *biom, int (*create) (BIO *));
+extern int (*BIO_meth_set_ctrl)(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *));
+extern int (*BIO_meth_set_destroy)(BIO_METHOD *biom, int (*destroy) (BIO *));
+extern int (*BIO_meth_set_gets)(BIO_METHOD *biom, int (*gets) (BIO *, char *, int));
+extern int (*BIO_meth_set_puts)(BIO_METHOD *biom, int (*puts) (BIO *, const char *));
+extern int (*BIO_meth_set_read)(BIO_METHOD *biom, int (*read) (BIO *, char *, int));
+extern int (*BIO_meth_set_write)(BIO_METHOD *biom, int (*write) (BIO *, const char *, int));
+extern BIO_METHOD *(*BIO_meth_new)(int type, const char *name);
+extern BIO *(*BIO_new)(const BIO_METHOD *type);
+extern void (*BIO_set_data)(BIO *a, void *ptr);
+extern void (*BIO_set_init)(BIO *a, int init);
+
+extern void (*CRYPTO_free)(void *ptr, const char *file, int line);
+extern void *(*CRYPTO_malloc)(size_t num, const char *file, int line);
+extern int (*CRYPTO_num_locks)(void);
+extern void (*CRYPTO_set_locking_callback)(void (*func)(int mode, int type, const char *file, int line));
+extern int (*CRYPTO_set_mem_functions)(void *(*m)(size_t bytes), void *(*r)(void *mem, size_t size), void (*f)(void *mem));
+extern int (*CRYPTO_THREADID_set_callback)(void (*func)(CRYPTO_THREADID *id));
+extern void (*CRYPTO_THREADID_set_numeric)(CRYPTO_THREADID *id, unsigned long val);
+
+extern char *(*ERR_error_string)(unsigned long e, char *buf);
+extern void (*ERR_error_string_n)(unsigned long e, char *buf, size_t len);
+extern unsigned long (*ERR_get_error)(void);
+
+# define OPENSSL_malloc(num) CRYPTO_malloc(num, __FILE__, __LINE__)
+# define OPENSSL_free(addr) CRYPTO_free(addr, __FILE__, __LINE__)
+
+extern int (*SSL_connect)(SSL *ssl);
+extern long (*SSL_ctrl)(SSL *ssl, int cmd, long arg, void *parg);
+extern void (*SSL_free)(SSL *ssl);
+extern int (*SSL_get_error)(SSL *ssl, int ret);
+extern X509 *(*SSL_get_peer_certificate)(const SSL *ssl);
+extern long (*SSL_get_verify_result)(const SSL *ssl);
+extern int (*SSL_library_init)(void);
+extern void (*SSL_load_error_strings)(void);
+extern SSL *(*SSL_new)(SSL_CTX *ctx);
+extern int (*SSL_read)(SSL *ssl, const void *buf, int num);
+extern void (*SSL_set_bio)(SSL *ssl, BIO *rbio, BIO *wbio);
+extern int (*SSL_shutdown)(SSL *ssl);
+extern int (*SSL_write)(SSL *ssl, const void *buf, int num);
+
+# define SSL_set_tlsext_host_name(s, name) SSL_ctrl((s), SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (char *)(name));
+
+extern long (*SSL_CTX_ctrl)(SSL_CTX *ctx, int cmd, long larg, void *parg);
+extern void (*SSL_CTX_free)(SSL_CTX *ctx);
+extern SSL_CTX *(*SSL_CTX_new)(const SSL_METHOD *method);
+extern int (*SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
+extern int (*SSL_CTX_set_default_verify_paths)(SSL_CTX *ctx);
+extern long (*SSL_CTX_set_options)(SSL_CTX *ctx, long options);
+extern void (*SSL_CTX_set_verify)(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *));
+extern int (*SSL_CTX_load_verify_locations)(SSL_CTX *ctx, const char *CAfile, const char *CApath);
+
+# define SSL_CTX_set_mode(ctx, mode) SSL_CTX_ctrl((ctx), SSL_CTRL_MODE, (mode), NULL);
+
+extern const SSL_METHOD *(*SSLv23_method)(void);
+extern const SSL_METHOD *(*TLS_method)(void);
+
+extern ASN1_STRING *(*X509_NAME_ENTRY_get_data)(const X509_NAME_ENTRY *ne);
+extern X509_NAME_ENTRY *(*X509_NAME_get_entry)(X509_NAME *name, int loc);
+extern int (*X509_NAME_get_index_by_NID)(X509_NAME *name, int nid, int lastpos);
+extern void (*X509_free)(X509 *a);
+extern void *(*X509_get_ext_d2i)(const X509 *x, int nid, int *crit, int *idx);
+extern X509_NAME *(*X509_get_subject_name)(const X509 *x);
+
+extern int (*i2d_X509)(X509 *a, unsigned char **ppout);
+
+extern int (*OPENSSL_sk_num)(const void *sk);
+extern void *(*OPENSSL_sk_value)(const void *sk, int i);
+extern void (*OPENSSL_sk_free)(void *sk);
+
+extern int (*sk_num)(const void *sk);
+extern void *(*sk_value)(const void *sk, int i);
+extern void (*sk_free)(void *sk);
+
+extern int sk_GENERAL_NAME_num(const GENERAL_NAME *sk);
+extern GENERAL_NAME *sk_GENERAL_NAME_value(const GENERAL_NAME *sk, int i);
+extern void GENERAL_NAMES_free(GENERAL_NAME *sk);
+
+extern int git_openssl_stream_dynamic_init(void);
+
+#endif /* GIT_OPENSSL_DYNAMIC */
+
+#endif
diff --git a/src/streams/openssl_legacy.c b/src/streams/openssl_legacy.c
new file mode 100644 (file)
index 0000000..e61e6ef
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "streams/openssl.h"
+#include "streams/openssl_legacy.h"
+
+#include "runtime.h"
+#include "git2/sys/openssl.h"
+
+#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC)
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509v3.h>
+# include <openssl/bio.h>
+#endif
+
+#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC)
+
+/*
+ * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
+ * which do not exist in previous versions. We define these inline functions so
+ * we can program against the interface instead of littering the implementation
+ * with ifdefs. We do the same for OPENSSL_init_ssl.
+ */
+
+int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings)
+{
+       GIT_UNUSED(opts);
+       GIT_UNUSED(settings);
+       SSL_load_error_strings();
+       SSL_library_init();
+       return 0;
+}
+
+BIO_METHOD *BIO_meth_new__legacy(int type, const char *name)
+{
+       BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
+       if (!meth) {
+               return NULL;
+       }
+
+       meth->type = type;
+       meth->name = name;
+
+       return meth;
+}
+
+void BIO_meth_free__legacy(BIO_METHOD *biom)
+{
+       git__free(biom);
+}
+
+int BIO_meth_set_write__legacy(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
+{
+       biom->bwrite = write;
+       return 1;
+}
+
+int BIO_meth_set_read__legacy(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
+{
+       biom->bread = read;
+       return 1;
+}
+
+int BIO_meth_set_puts__legacy(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
+{
+       biom->bputs = puts;
+       return 1;
+}
+
+int BIO_meth_set_gets__legacy(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
+
+{
+       biom->bgets = gets;
+       return 1;
+}
+
+int BIO_meth_set_ctrl__legacy(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
+{
+       biom->ctrl = ctrl;
+       return 1;
+}
+
+int BIO_meth_set_create__legacy(BIO_METHOD *biom, int (*create) (BIO *))
+{
+       biom->create = create;
+       return 1;
+}
+
+int BIO_meth_set_destroy__legacy(BIO_METHOD *biom, int (*destroy) (BIO *))
+{
+       biom->destroy = destroy;
+       return 1;
+}
+
+int BIO_get_new_index__legacy(void)
+{
+       /* This exists as of 1.1 so before we'd just have 0 */
+       return 0;
+}
+
+void BIO_set_init__legacy(BIO *b, int init)
+{
+       b->init = init;
+}
+
+void BIO_set_data__legacy(BIO *a, void *ptr)
+{
+       a->ptr = ptr;
+}
+
+void *BIO_get_data__legacy(BIO *a)
+{
+       return a->ptr;
+}
+
+const unsigned char *ASN1_STRING_get0_data__legacy(const ASN1_STRING *x)
+{
+       return ASN1_STRING_data((ASN1_STRING *)x);
+}
+
+long SSL_CTX_set_options__legacy(SSL_CTX *ctx, long op)
+{
+       return SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, NULL);
+}
+
+# if defined(GIT_THREADS)
+static git_mutex *openssl_locks;
+
+static void openssl_locking_function(int mode, int n, const char *file, int line)
+{
+       int lock;
+
+       GIT_UNUSED(file);
+       GIT_UNUSED(line);
+
+       lock = mode & CRYPTO_LOCK;
+
+       if (lock)
+               (void)git_mutex_lock(&openssl_locks[n]);
+       else
+               git_mutex_unlock(&openssl_locks[n]);
+}
+
+static void shutdown_ssl_locking(void)
+{
+       int num_locks, i;
+
+       num_locks = CRYPTO_num_locks();
+       CRYPTO_set_locking_callback(NULL);
+
+       for (i = 0; i < num_locks; ++i)
+               git_mutex_free(&openssl_locks[i]);
+       git__free(openssl_locks);
+}
+
+static void threadid_cb(CRYPTO_THREADID *threadid)
+{
+       GIT_UNUSED(threadid);
+       CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
+}
+
+int git_openssl_set_locking(void)
+{
+       int num_locks, i;
+
+#ifndef GIT_THREADS
+       git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads");
+       return -1;
+#endif
+
+#ifdef GIT_OPENSSL_DYNAMIC
+       /*
+        * This function is required on legacy versions of OpenSSL; when building
+        * with dynamically-loaded OpenSSL, we detect whether we loaded it or not.
+        */
+       if (!CRYPTO_set_locking_callback)
+               return 0;
+#endif
+
+       CRYPTO_THREADID_set_callback(threadid_cb);
+
+       num_locks = CRYPTO_num_locks();
+       openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
+       GIT_ERROR_CHECK_ALLOC(openssl_locks);
+
+       for (i = 0; i < num_locks; i++) {
+               if (git_mutex_init(&openssl_locks[i]) != 0) {
+                       git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks");
+                       return -1;
+               }
+       }
+
+       CRYPTO_set_locking_callback(openssl_locking_function);
+       return git_runtime_shutdown_register(shutdown_ssl_locking);
+}
+#endif /* GIT_THREADS */
+
+#endif /* GIT_OPENSSL_LEGACY || GIT_OPENSSL_DYNAMIC */
diff --git a/src/streams/openssl_legacy.h b/src/streams/openssl_legacy.h
new file mode 100644 (file)
index 0000000..e6dae95
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_streams_openssl_legacy_h__
+#define INCLUDE_streams_openssl_legacy_h__
+
+#include "streams/openssl_dynamic.h"
+
+#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC)
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509v3.h>
+# include <openssl/bio.h>
+
+# if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+     (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#  define GIT_OPENSSL_LEGACY
+# endif
+#endif
+
+#if defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
+# define OPENSSL_init_ssl OPENSSL_init_ssl__legacy
+# define BIO_meth_new BIO_meth_new__legacy
+# define BIO_meth_free BIO_meth_free__legacy
+# define BIO_meth_set_write BIO_meth_set_write__legacy
+# define BIO_meth_set_read BIO_meth_set_read__legacy
+# define BIO_meth_set_puts BIO_meth_set_puts__legacy
+# define BIO_meth_set_gets BIO_meth_set_gets__legacy
+# define BIO_meth_set_ctrl BIO_meth_set_ctrl__legacy
+# define BIO_meth_set_create BIO_meth_set_create__legacy
+# define BIO_meth_set_destroy BIO_meth_set_destroy__legacy
+# define BIO_get_new_index BIO_get_new_index__legacy
+# define BIO_set_data BIO_set_data__legacy
+# define BIO_set_init BIO_set_init__legacy
+# define BIO_get_data BIO_get_data__legacy
+# define ASN1_STRING_get0_data ASN1_STRING_get0_data__legacy
+#endif
+
+#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC)
+
+extern int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings);
+extern BIO_METHOD *BIO_meth_new__legacy(int type, const char *name);
+extern void BIO_meth_free__legacy(BIO_METHOD *biom);
+extern int BIO_meth_set_write__legacy(BIO_METHOD *biom, int (*write) (BIO *, const char *, int));
+extern int BIO_meth_set_read__legacy(BIO_METHOD *biom, int (*read) (BIO *, char *, int));
+extern int BIO_meth_set_puts__legacy(BIO_METHOD *biom, int (*puts) (BIO *, const char *));
+extern int BIO_meth_set_gets__legacy(BIO_METHOD *biom, int (*gets) (BIO *, char *, int));
+extern int BIO_meth_set_ctrl__legacy(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *));
+extern int BIO_meth_set_create__legacy(BIO_METHOD *biom, int (*create) (BIO *));
+extern int BIO_meth_set_destroy__legacy(BIO_METHOD *biom, int (*destroy) (BIO *));
+extern int BIO_get_new_index__legacy(void);
+extern void BIO_set_data__legacy(BIO *a, void *ptr);
+extern void BIO_set_init__legacy(BIO *b, int init);
+extern void *BIO_get_data__legacy(BIO *a);
+extern const unsigned char *ASN1_STRING_get0_data__legacy(const ASN1_STRING *x);
+extern long SSL_CTX_set_options__legacy(SSL_CTX *ctx, long op);
+
+#endif
+
+#endif
index 284431207cebcee86813d856733604ae93cb34c0..e60e1cd63e887e1ee0c71406eca7c86a734088ed 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "streams/registry.h"
 
-#include "global.h"
+#include "runtime.h"
 #include "streams/tls.h"
 #include "streams/mbedtls.h"
 #include "streams/openssl.h"
@@ -33,8 +33,7 @@ int git_stream_registry_global_init(void)
        if (git_rwlock_init(&stream_registry.lock) < 0)
                return -1;
 
-       git__on_shutdown(shutdown_stream_registry);
-       return 0;
+       return git_runtime_shutdown_register(shutdown_stream_registry);
 }
 
 GIT_INLINE(void) stream_registration_cpy(
@@ -52,7 +51,7 @@ int git_stream_registry_lookup(git_stream_registration *out, git_stream_t type)
        git_stream_registration *target;
        int error = GIT_ENOTFOUND;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        switch(type) {
        case GIT_STREAM_STANDARD:
@@ -62,7 +61,7 @@ int git_stream_registry_lookup(git_stream_registration *out, git_stream_t type)
                target = &stream_registry.tls_callbacks;
                break;
        default:
-               assert(0);
+               git_error_set(GIT_ERROR_INVALID, "invalid stream type");
                return -1;
        }
 
@@ -82,7 +81,7 @@ int git_stream_registry_lookup(git_stream_registration *out, git_stream_t type)
 
 int git_stream_register(git_stream_t type, git_stream_registration *registration)
 {
-       assert(!registration || registration->init);
+       GIT_ASSERT(!registration || registration->init);
 
        GIT_ERROR_CHECK_VERSION(registration, GIT_STREAM_VERSION, "stream_registration");
 
index 33f7883cd9c8dd69d197b4bcd31ced6572b073d4..9415fe892374f77015cc2f77c9b050a7d8830dd0 100644 (file)
@@ -183,7 +183,9 @@ static int default_socket_stream_new(
 {
        git_socket_stream *st;
 
-       assert(out && host && port);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
+       GIT_ASSERT_ARG(port);
 
        st = git__calloc(1, sizeof(git_socket_stream));
        GIT_ERROR_CHECK_ALLOC(st);
@@ -217,7 +219,9 @@ int git_socket_stream_new(
        git_stream_registration custom = {0};
        int error;
 
-       assert(out && host && port);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
+       GIT_ASSERT_ARG(port);
 
        if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0)
                init = custom.init;
index a79d3cbf0d77057f409de75a16f33cb733df2ece..3f31d2541c77df319b9bad78d59ee4c34efebd84 100644 (file)
@@ -167,7 +167,7 @@ static ssize_t stransport_write(git_stream *stream, const char *data, size_t len
        if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr)
                return stransport_error(ret);
 
-       assert(processed < SSIZE_MAX);
+       GIT_ASSERT(processed < SSIZE_MAX);
        return (ssize_t)processed;
 }
 
@@ -251,7 +251,9 @@ static int stransport_wrap(
        stransport_stream *st;
        OSStatus ret;
 
-       assert(out && in && host);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(in);
+       GIT_ASSERT_ARG(host);
 
        st = git__calloc(1, sizeof(stransport_stream));
        GIT_ERROR_CHECK_ALLOC(st);
@@ -305,7 +307,8 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
        git_stream *stream = NULL;
        int error;
 
-       assert(out && host);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
 
        error = git_socket_stream_new(&stream, host, port);
 
index 6a251717b69a5679d64b9506590b6fa4c2a2ee28..e063a33f99ae922d37772e8781204e9c0f356530 100644 (file)
@@ -8,7 +8,6 @@
 #include "git2/errors.h"
 
 #include "common.h"
-#include "global.h"
 #include "streams/registry.h"
 #include "streams/tls.h"
 #include "streams/mbedtls.h"
@@ -21,7 +20,9 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port)
        git_stream_registration custom = {0};
        int error;
 
-       assert(out && host && port);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(host);
+       GIT_ASSERT_ARG(port);
 
        if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_TLS)) == 0) {
                init = custom.init;
@@ -50,7 +51,8 @@ int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host)
        int (*wrap)(git_stream **, git_stream *, const char *) = NULL;
        git_stream_registration custom = {0};
 
-       assert(out && in);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(in);
 
        if (git_stream_registry_lookup(&custom, GIT_STREAM_TLS) == 0) {
                wrap = custom.wrap;
index c32b9770a9a298f1e9a3c0b2e307865c8036b93b..7cbb9fa3a1a2fff17d6b4eecced4fd725684c533 100644 (file)
@@ -12,7 +12,6 @@
 #include "git2/types.h"
 #include "git2/index.h"
 #include "buffer.h"
-#include "buf_text.h"
 #include "vector.h"
 #include "posix.h"
 #include "config_backend.h"
@@ -249,24 +248,62 @@ out:
        return error;
 }
 
+int git_submodule_cache_init(git_strmap **out, git_repository *repo)
+{
+       int error = 0;
+       git_strmap *cache = NULL;
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       if ((error = git_strmap_new(&cache)) < 0)
+               return error;
+       if ((error = git_submodule__map(repo, cache)) < 0) {
+               git_submodule_cache_free(cache);
+               return error;
+       }
+       *out = cache;
+       return error;
+}
+
+int git_submodule_cache_free(git_strmap *cache)
+{
+       git_submodule *sm = NULL;
+       if (cache == NULL)
+               return 0;
+       git_strmap_foreach_value(cache, sm, {
+               git_submodule_free(sm);
+       });
+       git_strmap_free(cache);
+       return 0;
+}
+
 int git_submodule_lookup(
        git_submodule **out, /* NULL if user only wants to test existence */
        git_repository *repo,
        const char *name)    /* trailing slash is allowed */
+{
+       return git_submodule__lookup_with_cache(out, repo, name, repo->submodule_cache);
+}
+
+int git_submodule__lookup_with_cache(
+       git_submodule **out, /* NULL if user only wants to test existence */
+       git_repository *repo,
+       const char *name,    /* trailing slash is allowed */
+       git_strmap *cache)
 {
        int error;
        unsigned int location;
        git_submodule *sm;
 
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if (repo->is_bare) {
                git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
                return -1;
        }
 
-       if (repo->submodule_cache != NULL) {
-               if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) {
+       if (cache != NULL) {
+               if ((sm = git_strmap_get(cache, name)) != NULL) {
                        if (out) {
                                *out = sm;
                                GIT_REFCOUNT_INC(*out);
@@ -342,8 +379,10 @@ int git_submodule_lookup(
                /* If it's not configured, we still check if there's a repo at the path */
                if (git_repository_workdir(repo)) {
                        git_buf path = GIT_BUF_INIT;
-                       if (git_buf_join3(&path,
-                                         '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
+                       if (git_buf_join3(&path, '/',
+                                         git_repository_workdir(repo),
+                                         name, DOT_GIT) < 0 ||
+                           git_path_validate_workdir_buf(NULL, &path) < 0)
                                return -1;
 
                        if (git_path_exists(path.ptr))
@@ -380,7 +419,7 @@ int git_submodule_name_is_valid(git_repository *repo, const char *name, int flag
                git_buf_attach_notowned(&buf, name, strlen(name));
        }
 
-       isvalid =  git_path_isvalid(repo, buf.ptr, 0, flags);
+       isvalid =  git_path_validate(repo, buf.ptr, 0, flags);
        git_buf_dispose(&buf);
 
        return isvalid;
@@ -515,12 +554,13 @@ int git_submodule__map(git_repository *repo, git_strmap *map)
        int error = 0;
        git_index *idx = NULL;
        git_tree *head = NULL;
-       const char *wd = NULL;
        git_buf path = GIT_BUF_INIT;
        git_submodule *sm;
        git_config *mods = NULL;
+       bool has_workdir;
 
-       assert(repo && map);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(map);
 
        /* get sources that we will need to check */
        if (git_repository_index(&idx, repo) < 0)
@@ -528,12 +568,14 @@ int git_submodule__map(git_repository *repo, git_strmap *map)
        if (git_repository_head_tree(&head, repo) < 0)
                git_error_clear();
 
-       wd = git_repository_workdir(repo);
-       if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
+       has_workdir = git_repository_workdir(repo) != NULL;
+
+       if (has_workdir &&
+           (error = git_repository_workdir_path(&path, repo, GIT_MODULES_FILE)) < 0)
                goto cleanup;
 
        /* add submodule information from .gitmodules */
-       if (wd) {
+       if (has_workdir) {
                lfc_data data = { 0 };
                data.map = map;
                data.repo = repo;
@@ -560,7 +602,7 @@ int git_submodule__map(git_repository *repo, git_strmap *map)
                        goto cleanup;
        }
        /* shallow scan submodules in work tree as needed */
-       if (wd) {
+       if (has_workdir) {
                git_strmap_foreach_value(map, sm, {
                                submodule_load_from_wd_lite(sm);
                        });
@@ -644,7 +686,7 @@ static int submodule_repo_init(
        git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
        git_repository *subrepo = NULL;
 
-       error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
+       error = git_repository_workdir_path(&workdir, parent_repo, path);
        if (error < 0)
                goto cleanup;
 
@@ -698,7 +740,9 @@ int git_submodule_add_setup(
        git_repository *subrepo = NULL;
        bool path_occupied;
 
-       assert(repo && url && path);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(url);
+       GIT_ASSERT_ARG(path);
 
        /* see if there is already an entry for this submodule */
 
@@ -749,7 +793,7 @@ int git_submodule_add_setup(
 
        /* init submodule repository and add origin remote as needed */
 
-       error = git_buf_joinpath(&name, git_repository_workdir(repo), path);
+       error = git_repository_workdir_path(&name, repo, path);
        if (error < 0)
                goto cleanup;
 
@@ -799,7 +843,8 @@ int git_submodule_repo_init(
        git_config *cfg = NULL;
        git_buf buf = GIT_BUF_INIT;
 
-       assert(out && sm);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(sm);
 
        /* get the configured remote url of the submodule */
        if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
@@ -840,7 +885,7 @@ int git_submodule_clone(git_repository **out, git_submodule *submodule, const gi
        git_submodule_update_options sub_opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
        git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
 
-       assert(submodule);
+       GIT_ASSERT_ARG(submodule);
 
        if (given_opts)
                memcpy(&sub_opts, given_opts, sizeof(sub_opts));
@@ -854,10 +899,9 @@ int git_submodule_clone(git_repository **out, git_submodule *submodule, const gi
        opts.remote_cb = clone_return_origin;
        opts.remote_cb_payload = submodule;
 
-       git_buf_puts(&rel_path, git_repository_workdir(git_submodule_owner(submodule)));
-       git_buf_joinpath(&rel_path, git_buf_cstr(&rel_path), git_submodule_path(submodule));
-
-       GIT_ERROR_CHECK_ALLOC_BUF(&rel_path);
+       error = git_repository_workdir_path(&rel_path, git_submodule_owner(submodule), git_submodule_path(submodule));
+       if (error < 0)
+               goto cleanup;
 
        error = git_clone__submodule(&clone, git_submodule_url(submodule), git_buf_cstr(&rel_path), &opts);
        if (error < 0)
@@ -879,7 +923,7 @@ int git_submodule_add_finalize(git_submodule *sm)
        int error;
        git_index *index;
 
-       assert(sm);
+       GIT_ASSERT_ARG(sm);
 
        if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
                (error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
@@ -898,15 +942,14 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
        git_index_entry entry;
        struct stat st;
 
-       assert(sm);
+       GIT_ASSERT_ARG(sm);
 
        /* force reload of wd OID by git_submodule_open */
        sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
 
        if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
-               (error = git_buf_joinpath(
-                       &path, git_repository_workdir(sm->repo), sm->path)) < 0 ||
-               (error = git_submodule_open(&sm_repo, sm)) < 0)
+           (error = git_repository_workdir_path(&path, sm->repo, sm->path)) < 0 ||
+           (error = git_submodule_open(&sm_repo, sm)) < 0)
                goto cleanup;
 
        /* read stat information for submodule working directory */
@@ -969,25 +1012,25 @@ static const char *submodule_update_to_str(git_submodule_update_t update)
 
 git_repository *git_submodule_owner(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
        return submodule->repo;
 }
 
 const char *git_submodule_name(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
        return submodule->name;
 }
 
 const char *git_submodule_path(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
        return submodule->path;
 }
 
 const char *git_submodule_url(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
        return submodule->url;
 }
 
@@ -996,9 +1039,12 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur
        int error = 0;
        git_buf normalized = GIT_BUF_INIT;
 
-       assert(out && repo && url);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(url);
 
-       git_buf_sanitize(out);
+       if ((error = git_buf_sanitize(out)) < 0)
+               return error;
 
        /* We do this in all platforms in case someone on Windows created the .gitmodules */
        if (strchr(url, '\\')) {
@@ -1066,28 +1112,30 @@ static int write_mapped_var(git_repository *repo, const char *name, git_configma
 
 const char *git_submodule_branch(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
        return submodule->branch;
 }
 
 int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
 {
-
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        return write_var(repo, name, "branch", branch);
 }
 
 int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
 {
-       assert(repo && name && url);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(url);
 
        return write_var(repo, name, "url", url);
 }
 
 const git_oid *git_submodule_index_id(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
 
        if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID)
                return &submodule->index_oid;
@@ -1097,7 +1145,7 @@ const git_oid *git_submodule_index_id(git_submodule *submodule)
 
 const git_oid *git_submodule_head_id(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
 
        if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID)
                return &submodule->head_oid;
@@ -1107,7 +1155,7 @@ const git_oid *git_submodule_head_id(git_submodule *submodule)
 
 const git_oid *git_submodule_wd_id(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
 
        /* load unless we think we have a valid oid */
        if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
@@ -1128,28 +1176,32 @@ const git_oid *git_submodule_wd_id(git_submodule *submodule)
 
 git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_IGNORE_UNSPECIFIED);
+
        return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
                GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
 }
 
 int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
 {
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
 }
 
 git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_UPDATE_NONE);
+
        return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
                GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
 }
 
 int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
 {
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
 }
@@ -1157,13 +1209,14 @@ int git_submodule_set_update(git_repository *repo, const char *name, git_submodu
 git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
        git_submodule *submodule)
 {
-       assert(submodule);
+       GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_RECURSE_NO);
        return submodule->fetch_recurse;
 }
 
 int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
 {
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
 }
@@ -1185,7 +1238,7 @@ static int submodule_repo_create(
                GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
 
        /* Workdir: path to sub-repo working directory */
-       error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
+       error = git_repository_workdir_path(&workdir, parent_repo, path);
        if (error < 0)
                goto cleanup;
 
@@ -1260,7 +1313,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
        git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
        git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
 
-       assert(sm);
+       GIT_ASSERT_ARG(sm);
 
        if (_update_options)
                memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
@@ -1473,7 +1526,8 @@ static int git_submodule__open(
        unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
        const char *wd;
 
-       assert(sm && subrepo);
+       GIT_ASSERT_ARG(sm);
+       GIT_ASSERT_ARG(subrepo);
 
        if (git_repository__ensure_not_bare(
                        sm->repo, "open submodule repository") < 0)
@@ -1481,8 +1535,7 @@ static int git_submodule__open(
 
        wd = git_repository_workdir(sm->repo);
 
-       if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
-               git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
+       if (git_buf_join3(&path, '/', wd, sm->path, DOT_GIT) < 0)
                return -1;
 
        sm->flags = sm->flags &
@@ -1609,7 +1662,7 @@ int git_submodule_reload(git_submodule *sm, int force)
 
        GIT_UNUSED(force);
 
-       assert(sm);
+       GIT_ASSERT_ARG(sm);
 
        if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0)
                /* This should come with a warning, but we've no API for that */
@@ -1726,7 +1779,9 @@ int git_submodule_status(unsigned int *status, git_repository *repo, const char
        git_submodule *sm;
        int error;
 
-       assert(status && repo && name);
+       GIT_ASSERT_ARG(status);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
                return error;
@@ -1739,7 +1794,8 @@ int git_submodule_status(unsigned int *status, git_repository *repo, const char
 
 int git_submodule_location(unsigned int *location, git_submodule *sm)
 {
-       assert(location && sm);
+       GIT_ASSERT_ARG(location);
+       GIT_ASSERT_ARG(sm);
 
        return git_submodule__status(
                location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
@@ -1798,6 +1854,17 @@ static void submodule_release(git_submodule *sm)
        git__free(sm);
 }
 
+int git_submodule_dup(git_submodule **out, git_submodule *source)
+{
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(source);
+
+       GIT_REFCOUNT_INC(source);
+
+       *out = source;
+       return 0;
+}
+
 void git_submodule_free(git_submodule *sm)
 {
        if (!sm)
@@ -2024,7 +2091,7 @@ static int submodule_load_from_wd_lite(git_submodule *sm)
 {
        git_buf path = GIT_BUF_INIT;
 
-       if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
+       if (git_repository_workdir_path(&path, sm->repo, sm->path) < 0)
                return -1;
 
        if (git_path_isdir(path.ptr))
@@ -2044,15 +2111,14 @@ static int submodule_load_from_wd_lite(git_submodule *sm)
  */
 static int gitmodules_snapshot(git_config **snap, git_repository *repo)
 {
-       const char *workdir = git_repository_workdir(repo);
        git_config *mods = NULL;
        git_buf path = GIT_BUF_INIT;
        int error;
 
-       if (!workdir)
+       if (git_repository_workdir(repo) == NULL)
                return GIT_ENOTFOUND;
 
-       if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
+       if ((error = git_repository_workdir_path(&path, repo, GIT_MODULES_FILE)) < 0)
                return error;
 
        if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
@@ -2076,12 +2142,11 @@ static git_config_backend *open_gitmodules(
        git_repository *repo,
        int okay_to_create)
 {
-       const char *workdir = git_repository_workdir(repo);
        git_buf path = GIT_BUF_INIT;
        git_config_backend *mods = NULL;
 
-       if (workdir != NULL) {
-               if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
+       if (git_repository_workdir(repo) != NULL) {
+               if (git_repository_workdir_path(&path, repo, GIT_MODULES_FILE) != 0)
                        return NULL;
 
                if (okay_to_create || git_path_isfile(path.ptr)) {
@@ -2194,8 +2259,9 @@ static int get_url_base(git_buf *url, git_repository *repo)
                if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
                        goto out;
                error = git_buf_sets(url, wt->parent_path);
-       } else
+       } else {
                error = git_buf_sets(url, git_repository_workdir(repo));
+       }
 
 out:
        git_remote_free(remote);
index 57d95c3fc8dcd5a4b02ddd785e5e920c4f09d07b..b01ff68a203595d3430542d2d545b3b1ef4c401f 100644 (file)
@@ -101,12 +101,6 @@ struct git_submodule {
        git_oid wd_oid;
 };
 
-/* Force revalidation of submodule data cache (alloc as needed) */
-extern int git_submodule_cache_refresh(git_repository *repo);
-
-/* Release all submodules */
-extern void git_submodule_cache_free(git_repository *repo);
-
 /* Additional flags on top of public GIT_SUBMODULE_STATUS values */
 enum {
        GIT_SUBMODULE_STATUS__WD_SCANNED          = (1u << 20),
@@ -122,9 +116,15 @@ enum {
 #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
        ((S) & ~(0xFFFFFFFFu << 20))
 
-/* Internal lookup does not attempt to refresh cached data */
-extern int git_submodule__lookup(
-       git_submodule **out, git_repository *repo, const char *path);
+/* Initialize an external submodule cache for the provided repo. */
+extern int git_submodule_cache_init(git_strmap **out, git_repository *repo);
+
+/* Release the resources of the submodule cache. */
+extern int git_submodule_cache_free(git_strmap *cache);
+
+/* Submodule lookup with an explicit cache */
+extern int git_submodule__lookup_with_cache(
+       git_submodule **out, git_repository *repo, const char *path, git_strmap *cache);
 
 /* Internal status fn returns status and optionally the various OIDs */
 extern int git_submodule__status(
index 6dc78c8fd997dd90c2d0c66e4c29bcdf4dd60bef..dcbd48bc3949d02dcb205436453f8dc0471afa6e 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "sysdir.h"
 
-#include "global.h"
+#include "runtime.h"
 #include "buffer.h"
 #include "path.h"
 #include <ctype.h>
@@ -45,7 +45,7 @@ static int get_passwd_home(git_buf *out, uid_t uid)
        long buflen;
        int error;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        if ((buflen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
                buflen = 1024;
@@ -189,9 +189,7 @@ int git_sysdir_global_init(void)
        for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++)
                error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf);
 
-       git__on_shutdown(git_sysdir_global_shutdown);
-
-       return error;
+       return git_runtime_shutdown_register(git_sysdir_global_shutdown);
 }
 
 static int git_sysdir_check_selector(git_sysdir_t which)
@@ -206,7 +204,7 @@ static int git_sysdir_check_selector(git_sysdir_t which)
 
 int git_sysdir_get(const git_buf **out, git_sysdir_t which)
 {
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        *out = NULL;
 
index 037dc6664748458108b0cd82a9c4171f3a988c93..ee91e509162ca53b057e7c09cb07c1421933214c 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -27,25 +27,25 @@ void git_tag__free(void *_tag)
 
 int git_tag_target(git_object **target, const git_tag *t)
 {
-       assert(t);
+       GIT_ASSERT_ARG(t);
        return git_object_lookup(target, t->object.repo, &t->target, t->type);
 }
 
 const git_oid *git_tag_target_id(const git_tag *t)
 {
-       assert(t);
+       GIT_ASSERT_ARG_WITH_RETVAL(t, NULL);
        return &t->target;
 }
 
 git_object_t git_tag_target_type(const git_tag *t)
 {
-       assert(t);
+       GIT_ASSERT_ARG_WITH_RETVAL(t, GIT_OBJECT_INVALID);
        return t->type;
 }
 
 const char *git_tag_name(const git_tag *t)
 {
-       assert(t);
+       GIT_ASSERT_ARG_WITH_RETVAL(t, NULL);
        return t->tag_name;
 }
 
@@ -56,7 +56,7 @@ const git_signature *git_tag_tagger(const git_tag *t)
 
 const char *git_tag_message(const git_tag *t)
 {
-       assert(t);
+       GIT_ASSERT_ARG_WITH_RETVAL(t, NULL);
        return t->message;
 }
 
@@ -259,8 +259,10 @@ static int git_tag_create__internal(
 
        int error;
 
-       assert(repo && tag_name && target);
-       assert(!create_tag_annotation || (tagger && message));
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(tag_name);
+       GIT_ASSERT_ARG(target);
+       GIT_ASSERT_ARG(!create_tag_annotation || (tagger && message));
 
        if (git_object_owner(target) != repo) {
                git_error_set(GIT_ERROR_INVALID, "the given target does not belong to this repository");
@@ -313,7 +315,12 @@ int git_tag_annotation_create(
        const git_signature *tagger,
        const char *message)
 {
-       assert(oid && repo && tag_name && target && tagger && message);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(tag_name);
+       GIT_ASSERT_ARG(target);
+       GIT_ASSERT_ARG(tagger);
+       GIT_ASSERT_ARG(message);
 
        return write_tag_annotation(oid, repo, tag_name, target, tagger, message);
 }
@@ -339,7 +346,8 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b
        git_reference *new_ref = NULL;
        git_buf ref_name = GIT_BUF_INIT;
 
-       assert(oid && buffer);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(buffer);
 
        memset(&tag, 0, sizeof(tag));
 
@@ -454,7 +462,8 @@ int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data)
 {
        tag_cb_data data;
 
-       assert(repo && cb);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(cb);
 
        data.cb = cb;
        data.cb_data = cb_data;
@@ -493,7 +502,9 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit
        tag_filter_data filter;
        git_vector taglist;
 
-       assert(tag_names && repo && pattern);
+       GIT_ASSERT_ARG(tag_names);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(pattern);
 
        if ((error = git_vector_init(&taglist, 8, NULL)) < 0)
                return error;
@@ -522,6 +533,31 @@ int git_tag_peel(git_object **tag_target, const git_tag *tag)
        return git_object_peel(tag_target, (const git_object *)tag, GIT_OBJECT_ANY);
 }
 
+int git_tag_name_is_valid(int *valid, const char *name)
+{
+       git_buf ref_name = GIT_BUF_INIT;
+       int error = 0;
+
+       GIT_ASSERT(valid);
+
+       /*
+        * Discourage tag name starting with dash,
+        * https://github.com/git/git/commit/4f0accd638b8d2
+        */
+       if (!name || name[0] == '-')
+               goto done;
+
+       if ((error = git_buf_puts(&ref_name, GIT_REFS_TAGS_DIR)) < 0 ||
+           (error = git_buf_puts(&ref_name, name)) < 0)
+               goto done;
+
+       error = git_reference_name_is_valid(valid, ref_name.ptr);
+
+done:
+       git_buf_dispose(&ref_name);
+       return error;
+}
+
 /* Deprecated Functions */
 
 #ifndef GIT_DEPRECATE_HARD
diff --git a/src/thread-utils.c b/src/thread-utils.c
deleted file mode 100644 (file)
index e5ec6a8..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "common.h"
-#include "thread-utils.h"
-
-#ifdef _WIN32
-#ifndef WIN32_LEAN_AND_MEAN
-#      define WIN32_LEAN_AND_MEAN
-#endif
-#      include <windows.h>
-#elif defined(hpux) || defined(__hpux) || defined(_hpux)
-#      include <sys/pstat.h>
-#endif
-
-/*
- * By doing this in two steps we can at least get
- * the function to be somewhat coherent, even
- * with this disgusting nest of #ifdefs.
- */
-#ifndef _SC_NPROCESSORS_ONLN
-#      ifdef _SC_NPROC_ONLN
-#              define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
-#      elif defined _SC_CRAY_NCPU
-#              define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
-#      endif
-#endif
-
-int git_online_cpus(void)
-{
-#ifdef _SC_NPROCESSORS_ONLN
-       long ncpus;
-#endif
-
-#ifdef _WIN32
-       SYSTEM_INFO info;
-       GetSystemInfo(&info);
-
-       if ((int)info.dwNumberOfProcessors > 0)
-               return (int)info.dwNumberOfProcessors;
-#elif defined(hpux) || defined(__hpux) || defined(_hpux)
-       struct pst_dynamic psd;
-
-       if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
-               return (int)psd.psd_proc_cnt;
-#endif
-
-#ifdef _SC_NPROCESSORS_ONLN
-       if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
-               return (int)ncpus;
-#endif
-
-       return 1;
-}
diff --git a/src/thread-utils.h b/src/thread-utils.h
deleted file mode 100644 (file)
index ecb4909..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_thread_utils_h__
-#define INCLUDE_thread_utils_h__
-
-#if defined(GIT_THREADS)
-
-#if defined(__clang__)
-
-# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1))
-#  error Atomic primitives do not exist on this version of clang; configure libgit2 with -DTHREADSAFE=OFF
-# else
-#  define GIT_BUILTIN_ATOMIC
-# endif
-
-#elif defined(__GNUC__)
-
-# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
-#  error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
-# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
-#  define GIT_BUILTIN_ATOMIC
-# else
-#  define GIT_BUILTIN_SYNC
-# endif
-
-#endif
-
-#endif /* GIT_THREADS */
-
-/* Common operations even if threading has been disabled */
-typedef struct {
-#if defined(GIT_WIN32)
-       volatile long val;
-#else
-       volatile int val;
-#endif
-} git_atomic;
-
-#ifdef GIT_ARCH_64
-
-typedef struct {
-#if defined(GIT_WIN32)
-       volatile __int64 val;
-#else
-       volatile int64_t val;
-#endif
-} git_atomic64;
-
-typedef git_atomic64 git_atomic_ssize;
-
-#define git_atomic_ssize_set git_atomic64_set
-#define git_atomic_ssize_add git_atomic64_add
-#define git_atomic_ssize_get git_atomic64_get
-
-#else
-
-typedef git_atomic git_atomic_ssize;
-
-#define git_atomic_ssize_set git_atomic_set
-#define git_atomic_ssize_add git_atomic_add
-#define git_atomic_ssize_get git_atomic_get
-
-#endif
-
-#ifdef GIT_THREADS
-
-#ifdef GIT_WIN32
-#   include "win32/thread.h"
-#else
-#   include "unix/pthread.h"
-#endif
-
-GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
-{
-#if defined(GIT_WIN32)
-       InterlockedExchange(&a->val, (LONG)val);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       __sync_lock_test_and_set(&a->val, val);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(int) git_atomic_inc(git_atomic *a)
-{
-#if defined(GIT_WIN32)
-       return InterlockedIncrement(&a->val);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_add_and_fetch(&a->val, 1);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
-{
-#if defined(GIT_WIN32)
-       return InterlockedExchangeAdd(&a->val, addend);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_add_and_fetch(&a->val, addend);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(int) git_atomic_dec(git_atomic *a)
-{
-#if defined(GIT_WIN32)
-       return InterlockedDecrement(&a->val);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_sub_and_fetch(&a->val, 1);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(int) git_atomic_get(git_atomic *a)
-{
-#if defined(GIT_WIN32)
-       return (int)InterlockedCompareExchange(&a->val, 0, 0);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_val_compare_and_swap(&a->val, 0, 0);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(void *) git___compare_and_swap(
-       void * volatile *ptr, void *oldval, void *newval)
-{
-#if defined(GIT_WIN32)
-       volatile void *foundval;
-       foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
-       return (foundval == oldval) ? oldval : newval;
-#elif defined(GIT_BUILTIN_ATOMIC)
-       bool success = __atomic_compare_exchange(ptr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
-       return success ? oldval : newval;
-#elif defined(GIT_BUILTIN_SYNC)
-       volatile void *foundval;
-       foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
-       return (foundval == oldval) ? oldval : newval;
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(volatile void *) git___swap(
-       void * volatile *ptr, void *newval)
-{
-#if defined(GIT_WIN32)
-       return InterlockedExchangePointer(ptr, newval);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       void * volatile foundval;
-       __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
-       return foundval;
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_lock_test_and_set(ptr, newval);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
-{
-#if defined(GIT_WIN32)
-       void *newval = NULL, *oldval = NULL;
-       volatile void *foundval = NULL;
-       foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
-       return foundval;
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-#ifdef GIT_ARCH_64
-
-GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
-{
-#if defined(GIT_WIN32)
-       return InterlockedExchangeAdd64(&a->val, addend);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_add_and_fetch(&a->val, addend);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
-{
-#if defined(GIT_WIN32)
-       InterlockedExchange64(&a->val, val);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       __sync_lock_test_and_set(&a->val, val);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
-{
-#if defined(GIT_WIN32)
-       return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0);
-#elif defined(GIT_BUILTIN_ATOMIC)
-       return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
-#elif defined(GIT_BUILTIN_SYNC)
-       return __sync_val_compare_and_swap(&a->val, 0, 0);
-#else
-#      error "Unsupported architecture for atomic operations"
-#endif
-}
-
-#endif
-
-#else
-
-#define git_thread unsigned int
-#define git_thread_create(thread, start_routine, arg) 0
-#define git_thread_join(id, status) (void)0
-
-/* Pthreads Mutex */
-#define git_mutex unsigned int
-GIT_INLINE(int) git_mutex_init(git_mutex *mutex) \
-       { GIT_UNUSED(mutex); return 0; }
-GIT_INLINE(int) git_mutex_lock(git_mutex *mutex) \
-       { GIT_UNUSED(mutex); return 0; }
-#define git_mutex_unlock(a) (void)0
-#define git_mutex_free(a) (void)0
-
-/* Pthreads condition vars */
-#define git_cond unsigned int
-#define git_cond_init(c, a)    (void)0
-#define git_cond_free(c) (void)0
-#define git_cond_wait(c, l)    (void)0
-#define git_cond_signal(c) (void)0
-#define git_cond_broadcast(c) (void)0
-
-/* Pthreads rwlock */
-#define git_rwlock unsigned int
-#define git_rwlock_init(a)             0
-#define git_rwlock_rdlock(a)   0
-#define git_rwlock_rdunlock(a) (void)0
-#define git_rwlock_wrlock(a)   0
-#define git_rwlock_wrunlock(a) (void)0
-#define git_rwlock_free(a)             (void)0
-#define GIT_RWLOCK_STATIC_INIT 0
-
-
-GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
-{
-       a->val = val;
-}
-
-GIT_INLINE(int) git_atomic_inc(git_atomic *a)
-{
-       return ++a->val;
-}
-
-GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
-{
-       a->val += addend;
-       return a->val;
-}
-
-GIT_INLINE(int) git_atomic_dec(git_atomic *a)
-{
-       return --a->val;
-}
-
-GIT_INLINE(int) git_atomic_get(git_atomic *a)
-{
-       return (int)a->val;
-}
-
-GIT_INLINE(void *) git___compare_and_swap(
-       void * volatile *ptr, void *oldval, void *newval)
-{
-       if (*ptr == oldval)
-               *ptr = newval;
-       else
-               oldval = newval;
-       return oldval;
-}
-
-GIT_INLINE(volatile void *) git___swap(
-       void * volatile *ptr, void *newval)
-{
-       volatile void *old = *ptr;
-       *ptr = newval;
-       return old;
-}
-
-#ifdef GIT_ARCH_64
-
-GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
-{
-       a->val += addend;
-       return a->val;
-}
-
-GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
-{
-       a->val = val;
-}
-
-GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
-{
-       return (int64_t)a->val;
-}
-
-#endif
-
-#endif
-
-/* Atomically replace oldval with newval
- * @return oldval if it was replaced or newval if it was not
- */
-#define git__compare_and_swap(P,O,N) \
-       git___compare_and_swap((void * volatile *)P, O, N)
-
-#define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
-
-#define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
-
-extern int git_online_cpus(void);
-
-#if defined(GIT_THREADS)
-
-# if defined(GIT_WIN32)
-#  define GIT_MEMORY_BARRIER MemoryBarrier()
-# elif defined(GIT_BUILTIN_ATOMIC)
-#  define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
-# elif defined(GIT_BUILTIN_SYNC)
-#  define GIT_MEMORY_BARRIER __sync_synchronize()
-# endif
-
-#else
-
-# define GIT_MEMORY_BARRIER /* noop */
-
-#endif
-
-#endif
diff --git a/src/thread.c b/src/thread.c
new file mode 100644 (file)
index 0000000..3171771
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+
+#if !defined(GIT_THREADS)
+
+#define TLSDATA_MAX 16
+
+typedef struct {
+       void *value;
+       void (GIT_SYSTEM_CALL *destroy_fn)(void *);
+} tlsdata_value;
+
+static tlsdata_value tlsdata_values[TLSDATA_MAX];
+static int tlsdata_cnt = 0;
+
+int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
+{
+       if (tlsdata_cnt >= TLSDATA_MAX)
+               return -1;
+
+       tlsdata_values[tlsdata_cnt].value = NULL;
+       tlsdata_values[tlsdata_cnt].destroy_fn = destroy_fn;
+
+       *key = tlsdata_cnt;
+       tlsdata_cnt++;
+
+       return 0;
+}
+
+int git_tlsdata_set(git_tlsdata_key key, void *value)
+{
+       if (key < 0 || key > tlsdata_cnt)
+               return -1;
+
+       tlsdata_values[key].value = value;
+       return 0;
+}
+
+void *git_tlsdata_get(git_tlsdata_key key)
+{
+       if (key < 0 || key > tlsdata_cnt)
+               return NULL;
+
+       return tlsdata_values[key].value;
+}
+
+int git_tlsdata_dispose(git_tlsdata_key key)
+{
+       void *value;
+       void (*destroy_fn)(void *) = NULL;
+
+       if (key < 0 || key > tlsdata_cnt)
+               return -1;
+
+       value = tlsdata_values[key].value;
+       destroy_fn = tlsdata_values[key].destroy_fn;
+
+       tlsdata_values[key].value = NULL;
+       tlsdata_values[key].destroy_fn = NULL;
+
+       if (value && destroy_fn)
+               destroy_fn(value);
+
+       return 0;
+}
+
+#elif defined(GIT_WIN32)
+
+int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
+{
+       DWORD fls_index = FlsAlloc(destroy_fn);
+
+       if (fls_index == FLS_OUT_OF_INDEXES)
+               return -1;
+
+       *key = fls_index;
+       return 0;
+}
+
+int git_tlsdata_set(git_tlsdata_key key, void *value)
+{
+       if (!FlsSetValue(key, value))
+               return -1;
+
+       return 0;
+}
+
+void *git_tlsdata_get(git_tlsdata_key key)
+{
+       return FlsGetValue(key);
+}
+
+int git_tlsdata_dispose(git_tlsdata_key key)
+{
+       if (!FlsFree(key))
+               return -1;
+
+       return 0;
+}
+
+#elif defined(_POSIX_THREADS)
+
+int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
+{
+       if (pthread_key_create(key, destroy_fn) != 0)
+               return -1;
+
+       return 0;
+}
+
+int git_tlsdata_set(git_tlsdata_key key, void *value)
+{
+       if (pthread_setspecific(key, value) != 0)
+               return -1;
+
+       return 0;
+}
+
+void *git_tlsdata_get(git_tlsdata_key key)
+{
+       return pthread_getspecific(key);
+}
+
+int git_tlsdata_dispose(git_tlsdata_key key)
+{
+       if (pthread_key_delete(key) != 0)
+               return -1;
+
+       return 0;
+}
+
+#else
+# error unknown threading model
+#endif
diff --git a/src/thread.h b/src/thread.h
new file mode 100644 (file)
index 0000000..4b091c0
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_thread_h__
+#define INCLUDE_thread_h__
+
+#if defined(GIT_THREADS)
+
+#if defined(__clang__)
+
+# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1))
+#  error Atomic primitives do not exist on this version of clang; configure libgit2 with -DTHREADSAFE=OFF
+# else
+#  define GIT_BUILTIN_ATOMIC
+# endif
+
+#elif defined(__GNUC__)
+
+# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
+#  error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
+# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#  define GIT_BUILTIN_ATOMIC
+# else
+#  define GIT_BUILTIN_SYNC
+# endif
+
+#endif
+
+#endif /* GIT_THREADS */
+
+/* Common operations even if threading has been disabled */
+typedef struct {
+#if defined(GIT_WIN32)
+       volatile long val;
+#else
+       volatile int val;
+#endif
+} git_atomic32;
+
+#ifdef GIT_ARCH_64
+
+typedef struct {
+#if defined(GIT_WIN32)
+       volatile __int64 val;
+#else
+       volatile int64_t val;
+#endif
+} git_atomic64;
+
+typedef git_atomic64 git_atomic_ssize;
+
+#define git_atomic_ssize_set git_atomic64_set
+#define git_atomic_ssize_add git_atomic64_add
+#define git_atomic_ssize_get git_atomic64_get
+
+#else
+
+typedef git_atomic32 git_atomic_ssize;
+
+#define git_atomic_ssize_set git_atomic32_set
+#define git_atomic_ssize_add git_atomic32_add
+#define git_atomic_ssize_get git_atomic32_get
+
+#endif
+
+#ifdef GIT_THREADS
+
+#ifdef GIT_WIN32
+#   include "win32/thread.h"
+#else
+#   include "unix/pthread.h"
+#endif
+
+/*
+ * Atomically sets the contents of *a to be val.
+ */
+GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
+{
+#if defined(GIT_WIN32)
+       InterlockedExchange(&a->val, (LONG)val);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       __sync_lock_test_and_set(&a->val, val);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically increments the contents of *a by 1, and stores the result back into *a.
+ * @return the result of the operation.
+ */
+GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
+{
+#if defined(GIT_WIN32)
+       return InterlockedIncrement(&a->val);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_add_and_fetch(&a->val, 1);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically adds the contents of *a and addend, and stores the result back into *a.
+ * @return the result of the operation.
+ */
+GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
+{
+#if defined(GIT_WIN32)
+       return InterlockedAdd(&a->val, addend);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_add_and_fetch(&a->val, addend);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically decrements the contents of *a by 1, and stores the result back into *a.
+ * @return the result of the operation.
+ */
+GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
+{
+#if defined(GIT_WIN32)
+       return InterlockedDecrement(&a->val);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_sub_and_fetch(&a->val, 1);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically gets the contents of *a.
+ * @return the contents of *a.
+ */
+GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
+{
+#if defined(GIT_WIN32)
+       return (int)InterlockedCompareExchange(&a->val, 0, 0);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_val_compare_and_swap(&a->val, 0, 0);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+GIT_INLINE(void *) git_atomic__compare_and_swap(
+       void * volatile *ptr, void *oldval, void *newval)
+{
+#if defined(GIT_WIN32)
+       return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       void *foundval = oldval;
+       __atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+       return foundval;
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_val_compare_and_swap(ptr, oldval, newval);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+GIT_INLINE(volatile void *) git_atomic__swap(
+       void * volatile *ptr, void *newval)
+{
+#if defined(GIT_WIN32)
+       return InterlockedExchangePointer(ptr, newval);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       void * volatile foundval = NULL;
+       __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
+       return foundval;
+#elif defined(GIT_BUILTIN_SYNC)
+       return (volatile void *)__sync_lock_test_and_set(ptr, newval);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
+{
+#if defined(GIT_WIN32)
+       void *newval = NULL, *oldval = NULL;
+       return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+#ifdef GIT_ARCH_64
+
+/*
+ * Atomically adds the contents of *a and addend, and stores the result back into *a.
+ * @return the result of the operation.
+ */
+GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
+{
+#if defined(GIT_WIN32)
+       return InterlockedAdd64(&a->val, addend);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_add_and_fetch(&a->val, addend);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically sets the contents of *a to be val.
+ */
+GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
+{
+#if defined(GIT_WIN32)
+       InterlockedExchange64(&a->val, val);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       __sync_lock_test_and_set(&a->val, val);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+/*
+ * Atomically gets the contents of *a.
+ * @return the contents of *a.
+ */
+GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
+{
+#if defined(GIT_WIN32)
+       return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0);
+#elif defined(GIT_BUILTIN_ATOMIC)
+       return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+       return __sync_val_compare_and_swap(&a->val, 0, 0);
+#else
+#      error "Unsupported architecture for atomic operations"
+#endif
+}
+
+#endif
+
+#else
+
+#define git_threads_global_init git__noop
+
+#define git_thread unsigned int
+#define git_thread_create(thread, start_routine, arg) git__noop()
+#define git_thread_join(id, status) git__noop()
+
+/* Pthreads Mutex */
+#define git_mutex unsigned int
+#define git_mutex_init(a)      git__noop()
+#define git_mutex_init(a)      git__noop()
+#define git_mutex_lock(a)      git__noop()
+#define git_mutex_unlock(a)    git__noop()
+#define git_mutex_free(a)      git__noop()
+
+/* Pthreads condition vars */
+#define git_cond unsigned int
+#define git_cond_init(c)       git__noop()
+#define git_cond_free(c)       git__noop()
+#define git_cond_wait(c, l)    git__noop()
+#define git_cond_signal(c)     git__noop()
+#define git_cond_broadcast(c)  git__noop()
+
+/* Pthreads rwlock */
+#define git_rwlock unsigned int
+#define git_rwlock_init(a)     git__noop()
+#define git_rwlock_rdlock(a)   git__noop()
+#define git_rwlock_rdunlock(a) git__noop()
+#define git_rwlock_wrlock(a)   git__noop()
+#define git_rwlock_wrunlock(a) git__noop()
+#define git_rwlock_free(a)     git__noop()
+#define GIT_RWLOCK_STATIC_INIT 0
+
+
+GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
+{
+       a->val = val;
+}
+
+GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
+{
+       return ++a->val;
+}
+
+GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
+{
+       a->val += addend;
+       return a->val;
+}
+
+GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
+{
+       return --a->val;
+}
+
+GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
+{
+       return (int)a->val;
+}
+
+GIT_INLINE(void *) git_atomic__compare_and_swap(
+       void * volatile *ptr, void *oldval, void *newval)
+{
+       void *foundval = *ptr;
+       if (foundval == oldval)
+               *ptr = newval;
+       return foundval;
+}
+
+GIT_INLINE(volatile void *) git_atomic__swap(
+       void * volatile *ptr, void *newval)
+{
+       volatile void *old = *ptr;
+       *ptr = newval;
+       return old;
+}
+
+GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
+{
+       return *ptr;
+}
+
+#ifdef GIT_ARCH_64
+
+GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
+{
+       a->val += addend;
+       return a->val;
+}
+
+GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
+{
+       a->val = val;
+}
+
+GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
+{
+       return (int64_t)a->val;
+}
+
+#endif
+
+#endif
+
+/*
+ * Atomically replace the contents of *ptr (if they are equal to oldval) with
+ * newval. ptr must point to a pointer or a value that is the same size as a
+ * pointer. This is semantically compatible with:
+ *
+ *   #define git_atomic_compare_and_swap(ptr, oldval, newval) \
+ *   ({                                                       \
+ *       void *foundval = *ptr;                               \
+ *       if (foundval == oldval)                              \
+ *           *ptr = newval;                                   \
+ *       foundval;                                            \
+ *   })
+ *
+ * @return the original contents of *ptr.
+ */
+#define git_atomic_compare_and_swap(ptr, oldval, newval) \
+       git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval)
+
+/*
+ * Atomically replace the contents of v with newval. v must be the same size as
+ * a pointer. This is semantically compatible with:
+ *
+ *   #define git_atomic_swap(v, newval) \
+ *   ({                                 \
+ *       volatile void *old = v;        \
+ *       v = newval;                    \
+ *       old;                           \
+ *   })
+ *
+ * @return the original contents of v.
+ */
+#define git_atomic_swap(v, newval) \
+       (void *)git_atomic__swap((void * volatile *)&(v), newval)
+
+/*
+ * Atomically reads the contents of v. v must be the same size as a pointer.
+ * This is semantically compatible with:
+ *
+ *   #define git_atomic_load(v) v
+ *
+ * @return the contents of v.
+ */
+#define git_atomic_load(v) \
+       (void *)git_atomic__load((void * volatile *)&(v))
+
+#if defined(GIT_THREADS)
+
+# if defined(GIT_WIN32)
+#  define GIT_MEMORY_BARRIER MemoryBarrier()
+# elif defined(GIT_BUILTIN_ATOMIC)
+#  define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
+# elif defined(GIT_BUILTIN_SYNC)
+#  define GIT_MEMORY_BARRIER __sync_synchronize()
+# endif
+
+#else
+
+# define GIT_MEMORY_BARRIER /* noop */
+
+#endif
+
+/* Thread-local data */
+
+#if !defined(GIT_THREADS)
+# define git_tlsdata_key int
+#elif defined(GIT_WIN32)
+# define git_tlsdata_key DWORD
+#elif defined(_POSIX_THREADS)
+# define git_tlsdata_key pthread_key_t
+#else
+# error unknown threading model
+#endif
+
+/**
+ * Create a thread-local data key.  The destroy function will be
+ * called upon thread exit.  On some platforms, it may be called
+ * when all threads have deleted their keys.
+ *
+ * Note that the tlsdata functions do not set an error message on
+ * failure; this is because the error handling in libgit2 is itself
+ * handled by thread-local data storage.
+ *
+ * @param key the tlsdata key
+ * @param destroy_fn function pointer called upon thread exit
+ * @return 0 on success, non-zero on failure
+ */
+int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *));
+
+/**
+ * Set a the thread-local value for the given key.
+ *
+ * @param key the tlsdata key to store data on
+ * @param value the pointer to store
+ * @return 0 on success, non-zero on failure
+ */
+int git_tlsdata_set(git_tlsdata_key key, void *value);
+
+/**
+ * Get the thread-local value for the given key.
+ *
+ * @param key the tlsdata key to retrieve the value of
+ * @return the pointer stored with git_tlsdata_set
+ */
+void *git_tlsdata_get(git_tlsdata_key key);
+
+/**
+ * Delete the given thread-local key.
+ *
+ * @param key the tlsdata key to dispose
+ * @return 0 on success, non-zero on failure
+ */
+int git_tlsdata_dispose(git_tlsdata_key key);
+
+#endif
diff --git a/src/threadstate.c b/src/threadstate.c
new file mode 100644 (file)
index 0000000..e2c0897
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "threadstate.h"
+#include "runtime.h"
+
+/**
+ * Handle the thread-local state
+ *
+ * `git_threadstate_global_init` will be called as part
+ * of `git_libgit2_init` (which itself must be called
+ * before calling any other function in the library).
+ *
+ * This function allocates a TLS index to store the per-
+ * thread state.
+ *
+ * Any internal method that requires thread-local state
+ * will then call `git_threadstate_get()` which returns a
+ * pointer to the thread-local state structure; this
+ * structure is lazily allocated on each thread.
+ *
+ * This mechanism will register a shutdown handler
+ * (`git_threadstate_global_shutdown`) which will free the
+ * TLS index.  This shutdown handler will be called by
+ * `git_libgit2_shutdown`.
+ */
+
+static git_tlsdata_key tls_key;
+
+static void threadstate_dispose(git_threadstate *threadstate)
+{
+       if (!threadstate)
+               return;
+
+    if (threadstate->error_t.message != git_buf__initbuf)
+        git__free(threadstate->error_t.message);
+       threadstate->error_t.message = NULL;
+}
+
+static void GIT_SYSTEM_CALL threadstate_free(void *threadstate)
+{
+       threadstate_dispose(threadstate);
+       git__free(threadstate);
+}
+
+static void git_threadstate_global_shutdown(void)
+{
+       git_threadstate *threadstate;
+
+       threadstate = git_tlsdata_get(tls_key);
+       git_tlsdata_set(tls_key, NULL);
+
+       threadstate_dispose(threadstate);
+       git__free(threadstate);
+
+       git_tlsdata_dispose(tls_key);
+}
+
+int git_threadstate_global_init(void)
+{
+       if (git_tlsdata_init(&tls_key, &threadstate_free) != 0)
+               return -1;
+
+       return git_runtime_shutdown_register(git_threadstate_global_shutdown);
+}
+
+git_threadstate *git_threadstate_get(void)
+{
+       git_threadstate *threadstate;
+
+       if ((threadstate = git_tlsdata_get(tls_key)) != NULL)
+               return threadstate;
+
+       if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
+           git_buf_init(&threadstate->error_buf, 0) < 0)
+               return NULL;
+
+       git_tlsdata_set(tls_key, threadstate);
+       return threadstate;
+}
diff --git a/src/threadstate.h b/src/threadstate.h
new file mode 100644 (file)
index 0000000..51810a9
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_threadstate_h__
+#define INCLUDE_threadstate_h__
+
+#include "common.h"
+
+typedef struct {
+       git_error *last_error;
+       git_error error_t;
+       git_buf error_buf;
+       char oid_fmt[GIT_OID_HEXSZ+1];
+} git_threadstate;
+
+extern int git_threadstate_global_init(void);
+extern git_threadstate *git_threadstate_get(void);
+
+#define GIT_THREADSTATE (git_threadstate_get())
+
+#endif
index ec6a90aad2a3fcf22dfb2e9857f1e007e38f8500..efc7b01a2d8d0f0891abd302ee6de9f0af1e2ebd 100644 (file)
@@ -8,7 +8,7 @@
 #include "trace.h"
 
 #include "buffer.h"
-#include "global.h"
+#include "runtime.h"
 #include "git2/trace.h"
 
 #ifdef GIT_TRACE
@@ -20,7 +20,7 @@ struct git_trace_data git_trace__data = {0};
 int git_trace_set(git_trace_level_t level, git_trace_cb callback)
 {
 #ifdef GIT_TRACE
-       assert(level == 0 || callback != NULL);
+       GIT_ASSERT_ARG(level == 0 || callback != NULL);
 
        git_trace__data.level = level;
        git_trace__data.callback = callback;
index e15118ef55e54c67e77bf511242c04d35ec30642..a233aa2257c3518f98c7eac699a3b644eb5b4efc 100644 (file)
@@ -23,28 +23,32 @@ extern struct git_trace_data git_trace__data;
 
 GIT_INLINE(void) git_trace__write_fmt(
        git_trace_level_t level,
-       const char *fmt, ...)
+       const char *fmt,
+       va_list ap)
 {
        git_trace_cb callback = git_trace__data.callback;
        git_buf message = GIT_BUF_INIT;
-       va_list ap;
 
-       va_start(ap, fmt);
        git_buf_vprintf(&message, fmt, ap);
-       va_end(ap);
 
        callback(level, git_buf_cstr(&message));
 
        git_buf_dispose(&message);
 }
 
-#define git_trace_level()              (git_trace__data.level)
-#define git_trace(l, ...)              { \
-                                                                       if (git_trace__data.level >= l && \
-                                                                               git_trace__data.callback != NULL) { \
-                                                                               git_trace__write_fmt(l, __VA_ARGS__); \
-                                                                       } \
-                                                               }
+#define git_trace_level()      (git_trace__data.level)
+
+GIT_INLINE(void) git_trace(git_trace_level_t level, const char *fmt, ...)
+{
+       if (git_trace__data.level >= level &&
+           git_trace__data.callback != NULL) {
+               va_list ap;
+
+               va_start(ap, fmt);
+               git_trace__write_fmt(level, fmt, ap);
+               va_end(ap);
+       }
+}
 
 #else
 
@@ -56,8 +60,8 @@ GIT_INLINE(void) git_trace__null(
        GIT_UNUSED(fmt);
 }
 
-#define git_trace_level()              ((git_trace_level_t)0)
-#define git_trace                      git_trace__null
+#define git_trace_level()      ((git_trace_level_t)0)
+#define git_trace              git_trace__null
 
 #endif
 
index ca81fd0205dab7b80b7c9c117c32b4a24aeabe21..61cdd1ba170783a812689a4219508d8e86806784 100644 (file)
@@ -258,7 +258,7 @@ static size_t find_trailer_end(const char *buf, size_t len)
        return len - ignore_non_trailer(buf, len);
 }
 
-static char *extract_trailer_block(const char *message, size_tlen)
+static char *extract_trailer_block(const char *message, size_t *len)
 {
        size_t patch_start = find_patch_start(message);
        size_t trailer_end = find_trailer_end(message, patch_start);
index 81af8d831531dcd81ab7c3110ee4eeafdcc3ed11..98fa1ba900ca49173d30874110235695e8aa32f7 100644 (file)
@@ -57,7 +57,9 @@ struct git_transaction {
 int git_transaction_config_new(git_transaction **out, git_config *cfg)
 {
        git_transaction *tx;
-       assert(out && cfg);
+
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(cfg);
 
        tx = git__calloc(1, sizeof(git_transaction));
        GIT_ERROR_CHECK_ALLOC(tx);
@@ -74,7 +76,8 @@ int git_transaction_new(git_transaction **out, git_repository *repo)
        git_pool pool;
        git_transaction *tx = NULL;
 
-       assert(out && repo);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
 
        if ((error = git_pool_init(&pool, 1)) < 0)
                goto on_error;
@@ -109,7 +112,8 @@ int git_transaction_lock_ref(git_transaction *tx, const char *refname)
        int error;
        transaction_node *node;
 
-       assert(tx && refname);
+       GIT_ASSERT_ARG(tx);
+       GIT_ASSERT_ARG(refname);
 
        node = git_pool_mallocz(&tx->pool, sizeof(transaction_node));
        GIT_ERROR_CHECK_ALLOC(node);
@@ -176,7 +180,9 @@ int git_transaction_set_target(git_transaction *tx, const char *refname, const g
        int error;
        transaction_node *node;
 
-       assert(tx && refname && target);
+       GIT_ASSERT_ARG(tx);
+       GIT_ASSERT_ARG(refname);
+       GIT_ASSERT_ARG(target);
 
        if ((error = find_locked(&node, tx, refname)) < 0)
                return error;
@@ -195,7 +201,9 @@ int git_transaction_set_symbolic_target(git_transaction *tx, const char *refname
        int error;
        transaction_node *node;
 
-       assert(tx && refname && target);
+       GIT_ASSERT_ARG(tx);
+       GIT_ASSERT_ARG(refname);
+       GIT_ASSERT_ARG(target);
 
        if ((error = find_locked(&node, tx, refname)) < 0)
                return error;
@@ -272,7 +280,9 @@ int git_transaction_set_reflog(git_transaction *tx, const char *refname, const g
        int error;
        transaction_node *node;
 
-       assert(tx && refname && reflog);
+       GIT_ASSERT_ARG(tx);
+       GIT_ASSERT_ARG(refname);
+       GIT_ASSERT_ARG(reflog);
 
        if ((error = find_locked(&node, tx, refname)) < 0)
                return error;
@@ -320,7 +330,7 @@ int git_transaction_commit(git_transaction *tx)
        transaction_node *node;
        int error = 0;
 
-       assert(tx);
+       GIT_ASSERT_ARG(tx);
 
        if (tx->type == TRANSACTION_CONFIG) {
                error = git_config_unlock(tx->cfg, true);
@@ -355,7 +365,8 @@ void git_transaction_free(git_transaction *tx)
        transaction_node *node;
        git_pool pool;
 
-       assert(tx);
+       if (!tx)
+               return;
 
        if (tx->type == TRANSACTION_CONFIG) {
                if (tx->cfg) {
index 227ee7dee3acab1c1c8201d08579dff3504af559..e128aa6c724f2b43f266844c8eddb8dec62669f3 100644 (file)
@@ -148,8 +148,8 @@ int git_transport_register(
        size_t i;
        int error = 0;
 
-       assert(scheme);
-       assert(cb);
+       GIT_ASSERT_ARG(scheme);
+       GIT_ASSERT_ARG(cb);
 
        if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
                goto on_error;
@@ -186,7 +186,7 @@ int git_transport_unregister(const char *scheme)
        size_t i;
        int error = 0;
 
-       assert(scheme);
+       GIT_ASSERT_ARG(scheme);
 
        if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
                goto done;
index 4aa3df02146d4c418196fcfa1257480805882482..51763e35926fc9e28c87c1c91a5235216e07b017 100644 (file)
@@ -18,7 +18,7 @@ static int basic_next_token(
 {
        git_credential_userpass_plaintext *cred;
        git_buf raw = GIT_BUF_INIT;
-       int error = -1;
+       int error = GIT_EAUTH;
 
        GIT_UNUSED(ctx);
 
index 8a614b81a3a2f24f7d861ce14a2906ed39dc5ab4..31469933e74825613657f64e4148f418ff54a26a 100644 (file)
@@ -65,7 +65,9 @@ static int negotiate_set_challenge(
 {
        http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
 
-       assert(ctx && ctx->configured && challenge);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(challenge);
+       GIT_ASSERT(ctx->configured);
 
        git__free(ctx->challenge);
 
@@ -108,7 +110,12 @@ static int negotiate_next_token(
        size_t challenge_len;
        int error = 0;
 
-       assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDENTIAL_DEFAULT);
+       GIT_ASSERT_ARG(buf);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(cred);
+
+       GIT_ASSERT(ctx->configured);
+       GIT_ASSERT(cred->credtype == GIT_CREDENTIAL_DEFAULT);
 
        if (ctx->complete)
                return 0;
@@ -202,7 +209,7 @@ static int negotiate_is_complete(git_http_auth_context *c)
 {
        http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
 
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
 
        return (ctx->complete == 1);
 }
@@ -260,7 +267,7 @@ static int negotiate_init_context(
 
        if (!ctx->oid) {
                git_error_set(GIT_ERROR_NET, "negotiate authentication is not supported");
-               return -1;
+               return GIT_EAUTH;
        }
 
        git_buf_puts(&ctx->target, "HTTP@");
index d134a3db6662789784cade1e5ab1ff02048e0f86..742db75b3d33ba822f4107295d4b41316da8b344 100644 (file)
@@ -14,7 +14,7 @@
 
 #ifdef GIT_NTLM
 
-#include "ntlm.h"
+#include "ntlmclient.h"
 
 typedef struct {
        git_http_auth_context parent;
@@ -29,7 +29,8 @@ static int ntlm_set_challenge(
 {
        http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
 
-       assert(ctx && challenge);
+       GIT_ASSERT_ARG(ctx);
+       GIT_ASSERT_ARG(challenge);
 
        git__free(ctx->challenge);
 
@@ -46,7 +47,7 @@ static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cr
        char *domain = NULL, *domainuser = NULL;
        int error = 0;
 
-       assert(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT);
+       GIT_ASSERT(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT);
        cred = (git_credential_userpass_plaintext *)_cred;
 
        if ((sep = strchr(cred->username, '\\')) != NULL) {
@@ -84,9 +85,12 @@ static int ntlm_next_token(
        git_buf input_buf = GIT_BUF_INIT;
        const unsigned char *msg;
        size_t challenge_len, msg_len;
-       int error = -1;
+       int error = GIT_EAUTH;
 
-       assert(buf && ctx && ctx->ntlm);
+       GIT_ASSERT_ARG(buf);
+       GIT_ASSERT_ARG(ctx);
+
+       GIT_ASSERT(ctx->ntlm);
 
        challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0;
 
@@ -162,7 +166,7 @@ static int ntlm_is_complete(git_http_auth_context *c)
 {
        http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
 
-       assert(ctx);
+       GIT_ASSERT_ARG(ctx);
        return (ctx->complete == true);
 }
 
index 7b2836445bc8fa668ab0030ccb893d656fd1efbd..6e00b02824373f4f5166e49fa2ba34be31938fd8 100644 (file)
@@ -85,7 +85,9 @@ int git_credential_userpass_plaintext_new(
 {
        git_credential_userpass_plaintext *c;
 
-       assert(cred && username && password);
+       GIT_ASSERT_ARG(cred);
+       GIT_ASSERT_ARG(username);
+       GIT_ASSERT_ARG(password);
 
        c = git__malloc(sizeof(git_credential_userpass_plaintext));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -233,7 +235,9 @@ static int git_credential_ssh_key_type_new(
 {
        git_credential_ssh_key *c;
 
-       assert(username && cred && privatekey);
+       GIT_ASSERT_ARG(username);
+       GIT_ASSERT_ARG(cred);
+       GIT_ASSERT_ARG(privatekey);
 
        c = git__calloc(1, sizeof(git_credential_ssh_key));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -269,7 +273,9 @@ int git_credential_ssh_interactive_new(
 {
        git_credential_ssh_interactive *c;
 
-       assert(out && username && prompt_callback);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(username);
+       GIT_ASSERT_ARG(prompt_callback);
 
        c = git__calloc(1, sizeof(git_credential_ssh_interactive));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -290,7 +296,8 @@ int git_credential_ssh_interactive_new(
 int git_credential_ssh_key_from_agent(git_credential **cred, const char *username) {
        git_credential_ssh_key *c;
 
-       assert(username && cred);
+       GIT_ASSERT_ARG(username);
+       GIT_ASSERT_ARG(cred);
 
        c = git__calloc(1, sizeof(git_credential_ssh_key));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -317,7 +324,8 @@ int git_credential_ssh_custom_new(
 {
        git_credential_ssh_custom *c;
 
-       assert(username && cred);
+       GIT_ASSERT_ARG(username);
+       GIT_ASSERT_ARG(cred);
 
        c = git__calloc(1, sizeof(git_credential_ssh_custom));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -347,7 +355,7 @@ int git_credential_default_new(git_credential **cred)
 {
        git_credential_default *c;
 
-       assert(cred);
+       GIT_ASSERT_ARG(cred);
 
        c = git__calloc(1, sizeof(git_credential_default));
        GIT_ERROR_CHECK_ALLOC(c);
@@ -364,7 +372,7 @@ int git_credential_username_new(git_credential **cred, const char *username)
        git_credential_username *c;
        size_t len, allocsize;
 
-       assert(cred);
+       GIT_ASSERT_ARG(cred);
 
        len = strlen(username);
 
index e48b7f961cca41d9b17a05c3d0524f659025035a..7c93155a8bf2928590226ea3a924cac8d3d24c34 100644 (file)
@@ -327,7 +327,7 @@ static int _git_close(git_smart_subtransport *subtransport)
 {
        git_subtransport *t = (git_subtransport *) subtransport;
 
-       assert(!t->current_stream);
+       GIT_ASSERT(!t->current_stream);
 
        GIT_UNUSED(t);
 
@@ -338,8 +338,6 @@ static void _git_free(git_smart_subtransport *subtransport)
 {
        git_subtransport *t = (git_subtransport *) subtransport;
 
-       assert(!t->current_stream);
-
        git__free(t);
 }
 
index 66731b0ce13c110b6cbf0e56065a61889b88a13a..914335aba57e929b920051a943aea432dc4a25e0 100644 (file)
@@ -14,7 +14,6 @@
 #include "buffer.h"
 #include "net.h"
 #include "netops.h"
-#include "global.h"
 #include "remote.h"
 #include "git2/sys/credential.h"
 #include "smart.h"
@@ -105,6 +104,11 @@ static int apply_url_credentials(
        const char *username,
        const char *password)
 {
+       GIT_ASSERT_ARG(username);
+
+       if (!password)
+               password = "";
+
        if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT)
                return git_credential_userpass_plaintext_new(cred, username, password);
 
@@ -139,8 +143,7 @@ static int handle_auth(
        /* Start with URL-specified credentials, if there were any. */
        if ((allowed_credtypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT) &&
            !server->url_cred_presented &&
-           server->url.username &&
-           server->url.password) {
+           server->url.username) {
                error = apply_url_credentials(&server->cred, allowed_credtypes, server->url.username, server->url.password);
                server->url_cred_presented = 1;
 
@@ -159,7 +162,7 @@ static int handle_auth(
 
        if (error > 0) {
                git_error_set(GIT_ERROR_HTTP, "%s authentication required but no callback set", server_type);
-               error = -1;
+               error = GIT_EAUTH;
        }
 
        if (!error)
@@ -176,7 +179,7 @@ GIT_INLINE(int) handle_remote_auth(
 
        if (response->server_auth_credtypes == 0) {
                git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support");
-               return -1;
+               return GIT_EAUTH;
        }
 
        /* Otherwise, prompt for credentials. */
@@ -198,7 +201,7 @@ GIT_INLINE(int) handle_proxy_auth(
 
        if (response->proxy_auth_credtypes == 0) {
                git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support");
-               return -1;
+               return GIT_EAUTH;
        }
 
        /* Otherwise, prompt for credentials. */
@@ -256,7 +259,7 @@ static int handle_response(
        } else if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED ||
                   response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
                git_error_set(GIT_ERROR_HTTP, "unexpected authentication failure");
-               return -1;
+               return GIT_EAUTH;
        }
 
        if (response->status != GIT_HTTP_STATUS_OK) {
@@ -287,7 +290,6 @@ static int lookup_proxy(
 {
        const char *proxy;
        git_remote *remote;
-       bool use_ssl;
        char *config = NULL;
        int error = 0;
 
@@ -301,9 +303,8 @@ static int lookup_proxy(
 
        case GIT_PROXY_AUTO:
                remote = transport->owner->owner;
-               use_ssl = !strcmp(transport->server.url.scheme, "https");
 
-               error = git_remote__get_http_proxy(remote, use_ssl, &config);
+               error = git_remote__http_proxy(&config, remote, &transport->server.url);
 
                if (error || !config)
                        goto done;
@@ -413,11 +414,11 @@ static int http_stream_read(
 
        if (stream->state == HTTP_STATE_SENDING_REQUEST) {
                git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
-               error = -1;
+               error = GIT_ERROR; /* not GIT_EAUTH, because the exact cause is unclear */
                goto done;
        }
 
-       assert (stream->state == HTTP_STATE_RECEIVING_RESPONSE);
+       GIT_ASSERT(stream->state == HTTP_STATE_RECEIVING_RESPONSE);
 
        error = git_http_client_read_body(transport->http_client, buffer, buffer_size);
 
@@ -551,11 +552,11 @@ static int http_stream_write(
        if (stream->state == HTTP_STATE_NONE) {
                git_error_set(GIT_ERROR_HTTP,
                              "too many redirects or authentication replays");
-               error = -1;
+               error = GIT_ERROR; /* not GIT_EAUTH because the exact cause is unclear */
                goto done;
        }
 
-       assert(stream->state == HTTP_STATE_SENDING_REQUEST);
+       GIT_ASSERT(stream->state == HTTP_STATE_SENDING_REQUEST);
 
        error = git_http_client_send_body(transport->http_client, buffer, len);
 
@@ -589,7 +590,7 @@ static int http_stream_read_response(
                    (error = handle_response(&complete, stream, &response, false)) < 0)
                    goto done;
 
-               assert(complete);
+               GIT_ASSERT(complete);
                stream->state = HTTP_STATE_RECEIVING_RESPONSE;
        }
 
@@ -638,7 +639,8 @@ static int http_action(
        const http_service *service;
        int error;
 
-       assert(out && t);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(t);
 
        *out = NULL;
 
@@ -721,7 +723,7 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own
 
        GIT_UNUSED(param);
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        transport = git__calloc(sizeof(http_subtransport), 1);
        GIT_ERROR_CHECK_ALLOC(transport);
index c02109cec07be83851931d3787ae17fdf0ad725a..5c360b88387666456df9ee2c02a0981a01106421 100644 (file)
@@ -9,6 +9,7 @@
 #define INCLUDE_transports_http_h__
 
 #include "buffer.h"
+#include "settings.h"
 #include "httpclient.h"
 
 #define GIT_HTTP_REPLAY_MAX 15
index ee936c81a64bb7603b635bf7d9cdb8a99004680f..5b8949a04dd2ed0f6f06846abd0e4938bdf600fe 100644 (file)
@@ -10,7 +10,6 @@
 #include "http_parser.h"
 #include "vector.h"
 #include "trace.h"
-#include "global.h"
 #include "httpclient.h"
 #include "http.h"
 #include "auth.h"
@@ -146,7 +145,8 @@ bool git_http_response_is_redirect(git_http_response *response)
 
 void git_http_response_dispose(git_http_response *response)
 {
-       assert(response);
+       if (!response)
+               return;
 
        git__free(response->content_type);
        git__free(response->location);
@@ -400,7 +400,7 @@ static int on_body(http_parser *parser, const char *buf, size_t len)
                return 0;
        }
 
-       assert(ctx->output_size >= ctx->output_written);
+       GIT_ASSERT(ctx->output_size >= ctx->output_written);
 
        max_len = min(ctx->output_size - ctx->output_written, len);
        max_len = min(max_len, INT_MAX);
@@ -597,7 +597,7 @@ static int apply_credentials(
                        free_auth_context(server);
        } else if (!token.size) {
                git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challenge");
-               error = -1;
+               error = GIT_EAUTH;
                goto done;
        }
 
@@ -631,6 +631,26 @@ GIT_INLINE(int) apply_proxy_credentials(
                                 request->proxy_credentials);
 }
 
+static int puts_host_and_port(git_buf *buf, git_net_url *url, bool force_port)
+{
+       bool ipv6 = git_net_url_is_ipv6(url);
+
+       if (ipv6)
+               git_buf_putc(buf, '[');
+
+       git_buf_puts(buf, url->host);
+
+       if (ipv6)
+               git_buf_putc(buf, ']');
+
+       if (force_port || !git_net_url_is_default_port(url)) {
+               git_buf_putc(buf, ':');
+               git_buf_puts(buf, url->port);
+       }
+
+       return git_buf_oom(buf) ? -1 : 0;
+}
+
 static int generate_connect_request(
        git_http_client *client,
        git_http_request *request)
@@ -641,14 +661,17 @@ static int generate_connect_request(
        git_buf_clear(&client->request_msg);
        buf = &client->request_msg;
 
-       git_buf_printf(buf, "CONNECT %s:%s HTTP/1.1\r\n",
-                      client->server.url.host, client->server.url.port);
+       git_buf_puts(buf, "CONNECT ");
+       puts_host_and_port(buf, &client->server.url, true);
+       git_buf_puts(buf, " HTTP/1.1\r\n");
 
        git_buf_puts(buf, "User-Agent: ");
        git_http__user_agent(buf);
        git_buf_puts(buf, "\r\n");
 
-       git_buf_printf(buf, "Host: %s\r\n", client->proxy.url.host);
+       git_buf_puts(buf, "Host: ");
+       puts_host_and_port(buf, &client->server.url, true);
+       git_buf_puts(buf, "\r\n");
 
        if ((error = apply_proxy_credentials(buf, client, request) < 0))
                return -1;
@@ -658,6 +681,11 @@ static int generate_connect_request(
        return git_buf_oom(buf) ? -1 : 0;
 }
 
+static bool use_connect_proxy(git_http_client *client)
+{
+    return client->proxy.url.host && !strcmp(client->server.url.scheme, "https");
+}
+
 static int generate_request(
        git_http_client *client,
        git_http_request *request)
@@ -666,7 +694,8 @@ static int generate_request(
        size_t i;
        int error;
 
-       assert(client && request);
+       GIT_ASSERT_ARG(client);
+       GIT_ASSERT_ARG(request);
 
        git_buf_clear(&client->request_msg);
        buf = &client->request_msg;
@@ -686,11 +715,8 @@ static int generate_request(
        git_http__user_agent(buf);
        git_buf_puts(buf, "\r\n");
 
-       git_buf_printf(buf, "Host: %s", request->url->host);
-
-       if (!git_net_url_is_default_port(request->url))
-               git_buf_printf(buf, ":%s", request->url->port);
-
+       git_buf_puts(buf, "Host: ");
+       puts_host_and_port(buf, request->url, false);
        git_buf_puts(buf, "\r\n");
 
        if (request->accept)
@@ -713,7 +739,8 @@ static int generate_request(
                git_buf_printf(buf, "Expect: 100-continue\r\n");
 
        if ((error = apply_server_credentials(buf, client, request)) < 0 ||
-           (error = apply_proxy_credentials(buf, client, request)) < 0)
+           (!use_connect_proxy(client) &&
+                       (error = apply_proxy_credentials(buf, client, request)) < 0))
                return error;
 
        if (request->custom_headers) {
@@ -843,7 +870,10 @@ static int setup_hosts(
 {
        int ret, diff = 0;
 
-       assert(client && request && request->url);
+       GIT_ASSERT_ARG(client);
+       GIT_ASSERT_ARG(request);
+
+       GIT_ASSERT(request->url);
 
        if ((ret = server_setup_from_url(&client->server, request->url)) < 0)
                return ret;
@@ -898,7 +928,7 @@ static int proxy_connect(
        int error;
 
        if (!client->proxy_connected || !client->keepalive) {
-               git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s:%s",
+               git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s port %s",
                          client->proxy.url.host, client->proxy.url.port);
 
                if ((error = server_create_stream(&client->proxy)) < 0 ||
@@ -923,7 +953,7 @@ static int proxy_connect(
            (error = git_http_client_skip_body(client)) < 0)
                goto done;
 
-       assert(client->state == DONE);
+       GIT_ASSERT(client->state == DONE);
 
        if (response.status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
                save_early_response(client, &response);
@@ -1003,8 +1033,7 @@ static int http_client_connect(
        reset_parser(client);
 
        /* Reconnect to the proxy if necessary. */
-       use_proxy = client->proxy.url.host &&
-                   !strcmp(client->server.url.scheme, "https");
+       use_proxy = use_connect_proxy(client);
 
        if (use_proxy) {
                if (!client->proxy_connected || !client->keepalive ||
@@ -1019,7 +1048,7 @@ static int http_client_connect(
                        goto on_error;
        }
 
-       git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s:%s",
+       git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s port %s",
                  client->server.url.host, client->server.url.port);
 
        if ((error = server_connect(client)) < 0)
@@ -1138,7 +1167,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
                 * final byte when paused in a callback.  Consume that byte.
                 * https://github.com/nodejs/http-parser/issues/97
                 */
-               assert(client->read_buf.size > parsed_len);
+               GIT_ASSERT(client->read_buf.size > parsed_len);
 
                http_parser_pause(parser, 0);
 
@@ -1216,7 +1245,8 @@ int git_http_client_send_request(
        git_http_response response = {0};
        int error = -1;
 
-       assert(client && request);
+       GIT_ASSERT_ARG(client);
+       GIT_ASSERT_ARG(request);
 
        /* If the client did not finish reading, clean up the stream. */
        if (client->state == READING_BODY)
@@ -1287,7 +1317,7 @@ int git_http_client_send_body(
        git_buf hdr = GIT_BUF_INIT;
        int error;
 
-       assert(client);
+       GIT_ASSERT_ARG(client);
 
        /* If we're waiting for proxy auth, don't sending more requests. */
        if (client->state == HAS_EARLY_RESPONSE)
@@ -1304,7 +1334,7 @@ int git_http_client_send_body(
        server = &client->server;
 
        if (client->request_body_len) {
-               assert(buffer_len <= client->request_body_remain);
+               GIT_ASSERT(buffer_len <= client->request_body_remain);
 
                if ((error = stream_write(server, buffer, buffer_len)) < 0)
                        goto done;
@@ -1327,7 +1357,8 @@ static int complete_request(git_http_client *client)
 {
        int error = 0;
 
-       assert(client && client->state == SENDING_BODY);
+       GIT_ASSERT_ARG(client);
+       GIT_ASSERT(client->state == SENDING_BODY);
 
        if (client->request_body_len && client->request_body_remain) {
                git_error_set(GIT_ERROR_HTTP, "truncated write");
@@ -1347,7 +1378,8 @@ int git_http_client_read_response(
        http_parser_context parser_context = {0};
        int error;
 
-       assert(response && client);
+       GIT_ASSERT_ARG(response);
+       GIT_ASSERT_ARG(client);
 
        if (client->state == SENDING_BODY) {
                if ((error = complete_request(client)) < 0)
@@ -1387,7 +1419,7 @@ int git_http_client_read_response(
                        goto done;
        }
 
-       assert(client->state == READING_BODY || client->state == DONE);
+       GIT_ASSERT(client->state == READING_BODY || client->state == DONE);
 
 done:
        git_buf_dispose(&parser_context.parse_header_name);
@@ -1440,7 +1472,7 @@ int git_http_client_read_body(
                        break;
        }
 
-       assert(parser_context.output_written <= INT_MAX);
+       GIT_ASSERT(parser_context.output_written <= INT_MAX);
        error = (int)parser_context.output_written;
 
 done:
@@ -1476,7 +1508,7 @@ int git_http_client_skip_body(git_http_client *client)
                                      "unexpected data handled in callback");
                        error = -1;
                }
-       } while (!error);
+       } while (error >= 0 && client->state != DONE);
 
        if (error < 0)
                client->connected = 0;
@@ -1494,7 +1526,7 @@ int git_http_client_new(
 {
        git_http_client *client;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        client = git__calloc(1, sizeof(git_http_client));
        GIT_ERROR_CHECK_ALLOC(client);
index 2a83bee3eb891ff8fb3c67f9f3867a4d3a751f08..6d0ef9edbf4bb2022c039a740561c1f89e35f645 100644 (file)
@@ -90,7 +90,7 @@ extern int git_http_client_new(
 
 /*
  * Sends a request to the host specified by the request URL.  If the
- * method is POST, either the the content_length or the chunked flag must
+ * method is POST, either the content_length or the chunked flag must
  * be specified.  The body should be provided in subsequent calls to
  * git_http_client_send_body.
  *
index 210de9f742ee89e6d115f9e8a8f03cc924ed34ec..bb31b1345809dfc2a28508ae47b02396601af2f0 100644 (file)
@@ -36,7 +36,7 @@ typedef struct {
        char *url;
        int direction;
        int flags;
-       git_atomic cancelled;
+       git_atomic32 cancelled;
        git_repository *repo;
        git_transport_message_cb progress_cb;
        git_transport_message_cb error_cb;
@@ -158,7 +158,7 @@ static int store_refs(transport_local *t)
        git_remote_head *head;
        git_strarray ref_names = {0};
 
-       assert(t);
+       GIT_ASSERT_ARG(t);
 
        if (git_reference_list(&ref_names, t->repo) < 0)
                goto on_error;
@@ -671,7 +671,7 @@ static void local_cancel(git_transport *transport)
 {
        transport_local *t = (transport_local *)transport;
 
-       git_atomic_set(&t->cancelled, 1);
+       git_atomic32_set(&t->cancelled, 1);
 }
 
 static int local_close(git_transport *transport)
index 5f5919407d73f7d4632654f4b8ed2a4e4f0f61d1..587f14358896955a0d3886f5acf65d1efa3c63d6 100644 (file)
@@ -18,7 +18,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
        size_t old_len, bytes_read;
        int error;
 
-       assert(t->current_stream);
+       GIT_ASSERT(t->current_stream);
 
        old_len = buf->offset;
 
@@ -30,7 +30,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
        if (t->packetsize_cb && !t->cancelled.val) {
                error = t->packetsize_cb(bytes_read, t->packetsize_payload);
                if (error) {
-                       git_atomic_set(&t->cancelled, 1);
+                       git_atomic32_set(&t->cancelled, 1);
                        return GIT_EUSER;
                }
        }
@@ -226,6 +226,8 @@ static int git_smart__connect(
        t->url = git__strdup(url);
        GIT_ERROR_CHECK_ALLOC(t->url);
 
+       git_proxy_options_clear(&t->proxy);
+
        if (git_proxy_options_dup(&t->proxy, proxy) < 0)
                return -1;
 
@@ -346,7 +348,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
                return error;
 
        /* If this is a stateful implementation, the stream we get back should be the same */
-       assert(t->rpc || t->current_stream == stream);
+       GIT_ASSERT(t->rpc || t->current_stream == stream);
 
        /* Save off the current stream (i.e. socket) that we are working with */
        t->current_stream = stream;
@@ -375,7 +377,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
                return error;
 
        /* If this is a stateful implementation, the stream we get back should be the same */
-       assert(t->rpc || t->current_stream == *stream);
+       GIT_ASSERT(t->rpc || t->current_stream == *stream);
 
        /* Save off the current stream (i.e. socket) that we are working with */
        t->current_stream = *stream;
@@ -389,7 +391,7 @@ static void git_smart__cancel(git_transport *transport)
 {
        transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
-       git_atomic_set(&t->cancelled, 1);
+       git_atomic32_set(&t->cancelled, 1);
 }
 
 static int git_smart__is_connected(git_transport *transport)
@@ -481,7 +483,9 @@ int git_transport_smart_certificate_check(git_transport *transport, git_cert *ce
 {
        transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
-       assert(transport && cert && hostname);
+       GIT_ASSERT_ARG(transport);
+       GIT_ASSERT_ARG(cert);
+       GIT_ASSERT_ARG(hostname);
 
        if (!t->certificate_check_cb)
                return GIT_PASSTHROUGH;
@@ -493,7 +497,8 @@ int git_transport_smart_credentials(git_credential **out, git_transport *transpo
 {
        transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
-       assert(out && transport);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(transport);
 
        if (!t->cred_acquire_cb)
                return GIT_PASSTHROUGH;
index 18e0b7e9fbaa88779bf3c754c16cdb2064727593..a05d4c9e3a287107eac80e9858c70061bd193b58 100644 (file)
@@ -153,7 +153,7 @@ typedef struct {
        git_vector refs;
        git_vector heads;
        git_vector common;
-       git_atomic cancelled;
+       git_atomic32 cancelled;
        packetsize_cb packetsize_cb;
        void *packetsize_payload;
        unsigned rpc : 1,
index c01656dc4698efaa1934a638d9a48d3645485032..91de163e91f23636142c234b0d37bbe7f5aa2ac8 100644 (file)
@@ -64,7 +64,9 @@ int git_smart__store_refs(transport_smart *t, int flushes)
                        continue;
                }
 
-               gitno_consume(buf, line_end);
+               if (gitno_consume(buf, line_end) < 0)
+                       return -1;
+
                if (pkt->type == GIT_PKT_ERR) {
                        git_error_set(GIT_ERROR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error);
                        git__free(pkt);
@@ -236,7 +238,9 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf
                }
        } while (error);
 
-       gitno_consume(buf, line_end);
+       if (gitno_consume(buf, line_end) < 0)
+               return -1;
+
        if (out_type != NULL)
                *out_type = pkt->type;
        if (out_pkt != NULL)
@@ -531,7 +535,7 @@ int git_smart__download_pack(
                /* We might have something in the buffer already from negotiate_fetch */
                if (t->buffer.offset > 0 && !t->cancelled.val)
                        if (t->packetsize_cb(t->buffer.offset, t->packetsize_payload))
-                               git_atomic_set(&t->cancelled, 1);
+                               git_atomic32_set(&t->cancelled, 1);
        }
 
        if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
@@ -791,7 +795,8 @@ static int parse_report(transport_smart *transport, git_push *push)
                        continue;
                }
 
-               gitno_consume(buf, line_end);
+               if (gitno_consume(buf, line_end) < 0)
+                       return -1;
 
                error = 0;
 
@@ -970,9 +975,10 @@ static int stream_thunk(void *buf, size_t size, void *data)
 
        if (payload->cb) {
                double current_time = git__timer();
+               double elapsed = current_time - payload->last_progress_report_time;
                payload->last_bytes += size;
 
-               if ((current_time - payload->last_progress_report_time) >= MIN_PROGRESS_UPDATE_INTERVAL) {
+               if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
                        payload->last_progress_report_time = current_time;
                        error = payload->cb(payload->pb->nr_written, payload->pb->nr_objects, payload->last_bytes, payload->cb_payload);
                }
index 68b3cbedab7c64e9a860b14461d9eb174844e609..1b00be79cd6bc04030a9b322526d58cd391a2c5c 100644 (file)
@@ -11,7 +11,7 @@
 #include <libssh2.h>
 #endif
 
-#include "global.h"
+#include "runtime.h"
 #include "git2.h"
 #include "buffer.h"
 #include "net.h"
@@ -238,7 +238,7 @@ static int ssh_stream_alloc(
 {
        ssh_stream *s;
 
-       assert(stream);
+       GIT_ASSERT_ARG(stream);
 
        s = git__calloc(sizeof(ssh_stream), 1);
        GIT_ERROR_CHECK_ALLOC(s);
@@ -404,8 +404,8 @@ static int _git_ssh_authenticate_session(
                case GIT_CREDENTIAL_SSH_MEMORY: {
                        git_credential_ssh_key *c = (git_credential_ssh_key *)cred;
 
-                       assert(c->username);
-                       assert(c->privatekey);
+                       GIT_ASSERT(c->username);
+                       GIT_ASSERT(c->privatekey);
 
                        rc = libssh2_userauth_publickey_frommemory(
                                session,
@@ -461,13 +461,13 @@ static int request_creds(git_credential **out, ssh_subtransport *t, const char *
 
        if (no_callback) {
                git_error_set(GIT_ERROR_SSH, "authentication required but no callback set");
-               return -1;
+               return GIT_EAUTH;
        }
 
        if (!(cred->credtype & auth_methods)) {
                cred->free(cred);
-               git_error_set(GIT_ERROR_SSH, "callback returned unsupported credentials type");
-               return -1;
+               git_error_set(GIT_ERROR_SSH, "authentication callback returned unsupported credentials type");
+               return GIT_EAUTH;
        }
 
        *out = cred;
@@ -476,14 +476,14 @@ static int request_creds(git_credential **out, ssh_subtransport *t, const char *
 }
 
 static int _git_ssh_session_create(
-       LIBSSH2_SESSION** session,
+       LIBSSH2_SESSION **session,
        git_stream *io)
 {
        int rc = 0;
-       LIBSSH2_SESSIONs;
+       LIBSSH2_SESSION *s;
        git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent);
 
-       assert(session);
+       GIT_ASSERT_ARG(session);
 
        s = libssh2_session_init();
        if (!s) {
@@ -521,8 +521,8 @@ static int _git_ssh_setup_conn(
        size_t i;
        ssh_stream *s;
        git_credential *cred = NULL;
-       LIBSSH2_SESSIONsession=NULL;
-       LIBSSH2_CHANNELchannel=NULL;
+       LIBSSH2_SESSION *session=NULL;
+       LIBSSH2_CHANNEL *channel=NULL;
 
        t->current_stream = NULL;
 
@@ -563,9 +563,46 @@ post_extract:
        if (t->owner->certificate_check_cb != NULL) {
                git_cert_hostkey cert = {{ 0 }}, *cert_ptr;
                const char *key;
+               size_t cert_len;
+               int cert_type;
 
                cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
 
+               key = libssh2_session_hostkey(session, &cert_len, &cert_type);
+               if (key != NULL) {
+                       cert.type |= GIT_CERT_SSH_RAW;
+                       cert.hostkey = key;
+                       cert.hostkey_len = cert_len;
+                       switch (cert_type) {
+                               case LIBSSH2_HOSTKEY_TYPE_RSA:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA;
+                                       break;
+                               case LIBSSH2_HOSTKEY_TYPE_DSS:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS;
+                                       break;
+                                       
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
+                               case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256;
+                                       break;
+                               case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384;
+                                       break;
+                               case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521;
+                                       break;
+#endif
+                                       
+#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
+                               case LIBSSH2_HOSTKEY_TYPE_ED25519:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519;
+                                       break;
+#endif
+                               default:
+                                       cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN;
+                       }
+               }
+
 #ifdef LIBSSH2_HOSTKEY_HASH_SHA256
                key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
                if (key != NULL) {
@@ -772,7 +809,7 @@ static int _ssh_close(git_smart_subtransport *subtransport)
 {
        ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent);
 
-       assert(!t->current_stream);
+       GIT_ASSERT(!t->current_stream);
 
        GIT_UNUSED(t);
 
@@ -783,8 +820,6 @@ static void _ssh_free(git_smart_subtransport *subtransport)
 {
        ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent);
 
-       assert(!t->current_stream);
-
        git__free(t->cmd_uploadpack);
        git__free(t->cmd_receivepack);
        git__free(t);
@@ -805,7 +840,7 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use
        /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */
        if (list == NULL && !libssh2_userauth_authenticated(session)) {
                ssh_error(session, "Failed to retrieve list of SSH authentication methods");
-               return -1;
+               return GIT_EAUTH;
        }
 
        ptr = list;
@@ -849,7 +884,7 @@ int git_smart_subtransport_ssh(
 #ifdef GIT_SSH
        ssh_subtransport *t;
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
 
        GIT_UNUSED(param);
 
@@ -867,7 +902,7 @@ int git_smart_subtransport_ssh(
        GIT_UNUSED(owner);
        GIT_UNUSED(param);
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
        *out = NULL;
 
        git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support");
@@ -911,7 +946,7 @@ int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *p
        GIT_UNUSED(owner);
        GIT_UNUSED(payload);
 
-       assert(out);
+       GIT_ASSERT_ARG(out);
        *out = NULL;
 
        git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support");
@@ -934,8 +969,7 @@ int git_transport_ssh_global_init(void)
                return -1;
        }
 
-       git__on_shutdown(shutdown_ssh);
-       return 0;
+       return git_runtime_shutdown_register(shutdown_ssh);
 
 #else
 
index f9736cd07f1e24407c844d130f4a7d49bbc56e9c..f4801a4516b6384d5231297acc2ea85187be3375 100644 (file)
@@ -17,7 +17,6 @@
 #include "smart.h"
 #include "remote.h"
 #include "repository.h"
-#include "global.h"
 #include "http.h"
 #include "git2/sys/credential.h"
 
 # define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 0x00002000
 #endif
 
+#ifndef WINHTTP_NO_CLIENT_CERT_CONTEXT
+# define WINHTTP_NO_CLIENT_CERT_CONTEXT NULL
+#endif
+
 #ifndef HTTP_STATUS_PERMANENT_REDIRECT
 # define HTTP_STATUS_PERMANENT_REDIRECT 308
 #endif
@@ -112,7 +115,8 @@ typedef struct {
        DWORD post_body_len;
        unsigned sent_request : 1,
                received_response : 1,
-               chunked : 1;
+               chunked : 1,
+               status_sending_request_reached: 1;
 } winhttp_stream;
 
 typedef struct {
@@ -150,7 +154,7 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha
                native_scheme = WINHTTP_AUTH_SCHEME_BASIC;
        } else {
                git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
-               error = -1;
+               error = GIT_EAUTH;
                goto done;
        }
 
@@ -189,7 +193,7 @@ static int apply_default_credentials(HINTERNET request, DWORD target, int mechan
                native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
        } else {
                git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
-               return -1;
+               return GIT_EAUTH;
        }
 
        /*
@@ -246,7 +250,7 @@ static int acquire_fallback_cred(
                hCoInitResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
 
                if (SUCCEEDED(hCoInitResult) || hCoInitResult == RPC_E_CHANGED_MODE) {
-                       IInternetSecurityManagerpISM;
+                       IInternetSecurityManager *pISM;
 
                        /* And if the target URI is in the My Computer, Intranet, or Trusted zones */
                        if (SUCCEEDED(CoCreateInstance(&CLSID_InternetSecurityManager, NULL,
@@ -269,7 +273,7 @@ static int acquire_fallback_cred(
                                pISM->lpVtbl->Release(pISM);
                        }
 
-                       /* Only unitialize if the call to CoInitializeEx was successful. */
+                       /* Only uninitialize if the call to CoInitializeEx was successful. */
                        if (SUCCEEDED(hCoInitResult))
                                CoUninitialize();
                }
@@ -425,7 +429,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
        proxy_opts = &t->owner->proxy;
        if (proxy_opts->type == GIT_PROXY_AUTO) {
                /* Set proxy if necessary */
-               if (git_remote__get_http_proxy(t->owner->owner, (strcmp(t->server.url.scheme, "https") == 0), &proxy_url) < 0)
+               if (git_remote__http_proxy(&proxy_url, t->owner->owner, &t->server.url) < 0)
                        goto on_error;
        }
        else if (proxy_opts->type == GIT_PROXY_SPECIFIED) {
@@ -452,8 +456,14 @@ static int winhttp_stream_connect(winhttp_stream *s)
                git_buf_puts(&processed_url, t->proxy.url.scheme);
                git_buf_PUTS(&processed_url, "://");
 
+               if (git_net_url_is_ipv6(&t->proxy.url))
+                       git_buf_putc(&processed_url, '[');
+
                git_buf_puts(&processed_url, t->proxy.url.host);
 
+               if (git_net_url_is_ipv6(&t->proxy.url))
+                       git_buf_putc(&processed_url, ']');
+
                if (!git_net_url_is_default_port(&t->proxy.url))
                        git_buf_printf(&processed_url, ":%s", t->proxy.url.port);
 
@@ -606,7 +616,7 @@ static int parse_unauthorized_response(
         */
        if (!WinHttpQueryAuthSchemes(request, &supported, &first, &target)) {
                git_error_set(GIT_ERROR_OS, "failed to parse supported auth schemes");
-               return -1;
+               return GIT_EAUTH;
        }
 
        if (WINHTTP_AUTH_SCHEME_NTLM & supported) {
@@ -708,39 +718,46 @@ static void CALLBACK winhttp_status(
        DWORD status;
 
        GIT_UNUSED(connection);
-       GIT_UNUSED(ctx);
        GIT_UNUSED(info_len);
 
-       if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
-               return;
-
-       status = *((DWORD *)info);
-
-       if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
-               git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
-               git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
-               git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
-               git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
-               git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
-               git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
-       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
-               git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
-       else
-               git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
+       switch (code) {
+               case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
+                       status = *((DWORD *)info);
+
+                       if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
+                               git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
+                               git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
+                               git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
+                               git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
+                               git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
+                               git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
+                       else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
+                               git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
+                       else
+                               git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
+
+                       break;
+
+               case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
+                       ((winhttp_stream *) ctx)->status_sending_request_reached = 1;
+
+                       break;
+       }
 }
 
 static int winhttp_connect(
        winhttp_subtransport *t)
 {
-       wchar_t *wide_host;
+       wchar_t *wide_host = NULL;
        int32_t port;
-       wchar_t *wide_ua;
-       git_buf ua = GIT_BUF_INIT;
+       wchar_t *wide_ua = NULL;
+       git_buf ipv6 = GIT_BUF_INIT, ua = GIT_BUF_INIT;
+       const char *host;
        int error = -1;
        int default_timeout = TIMEOUT_INFINITE;
        int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
@@ -756,29 +773,33 @@ static int winhttp_connect(
        /* Prepare port */
        if (git__strntol32(&port, t->server.url.port,
                           strlen(t->server.url.port), NULL, 10) < 0)
-               return -1;
+               goto on_error;
+
+       /* IPv6? Add braces around the host. */
+       if (git_net_url_is_ipv6(&t->server.url)) {
+               if (git_buf_printf(&ipv6, "[%s]", t->server.url.host) < 0)
+                       goto on_error;
+
+               host = ipv6.ptr;
+       } else {
+               host = t->server.url.host;
+       }
 
        /* Prepare host */
-       if (git__utf8_to_16_alloc(&wide_host, t->server.url.host) < 0) {
+       if (git__utf8_to_16_alloc(&wide_host, host) < 0) {
                git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
-               return -1;
+               goto on_error;
        }
 
 
-       if ((error = git_http__user_agent(&ua)) < 0) {
-               git__free(wide_host);
-               return error;
-       }
+       if (git_http__user_agent(&ua) < 0)
+               goto on_error;
 
        if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
                git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
-               git__free(wide_host);
-               git_buf_dispose(&ua);
-               return -1;
+               goto on_error;
        }
 
-       git_buf_dispose(&ua);
-
        /* Establish session */
        t->session = WinHttpOpen(
                wide_ua,
@@ -826,7 +847,12 @@ static int winhttp_connect(
                goto on_error;
        }
 
-       if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
+       if (WinHttpSetStatusCallback(
+                       t->connection,
+                       winhttp_status,
+                       WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST,
+                       0
+               ) == WINHTTP_INVALID_STATUS_CALLBACK) {
                git_error_set(GIT_ERROR_OS, "failed to set status callback");
                goto on_error;
        }
@@ -837,6 +863,8 @@ on_error:
        if (error < 0)
                winhttp_close_connection(t);
 
+       git_buf_dispose(&ua);
+       git_buf_dispose(&ipv6);
        git__free(wide_host);
        git__free(wide_ua);
 
@@ -858,12 +886,12 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
                        success = WinHttpSendRequest(s->request,
                                WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                WINHTTP_NO_REQUEST_DATA, 0,
-                               WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0);
+                               WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, (DWORD_PTR)s);
                } else {
                        success = WinHttpSendRequest(s->request,
                                WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                WINHTTP_NO_REQUEST_DATA, 0,
-                               (DWORD)len, 0);
+                               (DWORD)len, (DWORD_PTR)s);
                }
 
                if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL)
@@ -875,42 +903,71 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
 
 static int send_request(winhttp_stream *s, size_t len, bool chunked)
 {
-       int request_failed = 0, cert_valid = 1, error = 0;
-       DWORD ignore_flags;
+       int request_failed = 1, error, attempts = 0;
+       DWORD ignore_flags, send_request_error;
 
        git_error_clear();
-       if ((error = do_send_request(s, len, chunked)) < 0) {
-               if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
-                       git_error_set(GIT_ERROR_OS, "failed to send request");
-                       return -1;
-               }
 
-               request_failed = 1;
-               cert_valid = 0;
-       }
+       while (request_failed && attempts++ < 3) {
+               int cert_valid = 1;
+               int client_cert_requested = 0;
+               request_failed = 0;
+               if ((error = do_send_request(s, len, chunked)) < 0) {
+                       send_request_error = GetLastError();
+                       request_failed = 1;
+                       switch (send_request_error) {
+                               case ERROR_WINHTTP_SECURE_FAILURE:
+                                       cert_valid = 0;
+                                       break;
+                               case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
+                                       client_cert_requested = 1;
+                                       break;
+                               default:
+                                       git_error_set(GIT_ERROR_OS, "failed to send request");
+                                       return -1;
+                       }
+               }
 
-       git_error_clear();
-       if ((error = certificate_check(s, cert_valid)) < 0) {
-               if (!git_error_last())
-                       git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
+               /*
+                * Only check the certificate if we were able to reach the sending request phase, or
+                * received a secure failure error. Otherwise, the server certificate won't be available
+                * since the request wasn't able to complete (e.g. proxy auth required)
+                */
+               if (!cert_valid ||
+                       (!request_failed && s->status_sending_request_reached)) {
+                       git_error_clear();
+                       if ((error = certificate_check(s, cert_valid)) < 0) {
+                               if (!git_error_last())
+                                       git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
 
-               return error;
-       }
+                               return error;
+                       }
+               }
 
-       /* if neither the request nor the certificate check returned errors, we're done */
-       if (!request_failed)
-               return 0;
+               /* if neither the request nor the certificate check returned errors, we're done */
+               if (!request_failed)
+                       return 0;
 
-       ignore_flags = no_check_cert_flags;
+               if (!cert_valid) {
+                       ignore_flags = no_check_cert_flags;
+                       if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
+                               git_error_set(GIT_ERROR_OS, "failed to set security options");
+                               return -1;
+                       }
+               }
 
-       if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
-               git_error_set(GIT_ERROR_OS, "failed to set security options");
-               return -1;
+               if (client_cert_requested) {
+                       /*
+                        * Client certificates are not supported, explicitly tell the server that
+                        * (it's possible a client certificate was requested but is not required)
+                        */
+                       if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
+                               git_error_set(GIT_ERROR_OS, "failed to set client cert context");
+                               return -1;
+                       }
+               }
        }
 
-       if ((error = do_send_request(s, len, chunked)) < 0)
-               git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
-
        return error;
 }
 
@@ -983,7 +1040,7 @@ replay:
        /* Enforce a reasonable cap on the number of replays */
        if (replay_count++ >= GIT_HTTP_REPLAY_MAX) {
                git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
-               return -1;
+               return GIT_ERROR; /* not GIT_EAUTH because the exact cause is not clear */
        }
 
        /* Connect if necessary */
@@ -1004,7 +1061,7 @@ replay:
                }
 
                if (s->chunked) {
-                       assert(s->verb == post_verb);
+                       GIT_ASSERT(s->verb == post_verb);
 
                        /* Flush, if necessary */
                        if (s->chunk_buffer_len > 0 &&
@@ -1055,7 +1112,7 @@ replay:
                                }
 
                                len -= bytes_read;
-                               assert(bytes_read == bytes_written);
+                               GIT_ASSERT(bytes_read == bytes_written);
                        }
 
                        git__free(buffer);
@@ -1167,7 +1224,7 @@ replay:
                        if (error < 0) {
                                return error;
                        } else if (!error) {
-                               assert(t->server.cred);
+                               GIT_ASSERT(t->server.cred);
                                winhttp_stream_close(s);
                                goto replay;
                        }
@@ -1181,7 +1238,7 @@ replay:
                        if (error < 0) {
                                return error;
                        } else if (!error) {
-                               assert(t->proxy.cred);
+                               GIT_ASSERT(t->proxy.cred);
                                winhttp_stream_close(s);
                                goto replay;
                        }
@@ -1267,7 +1324,7 @@ static int winhttp_stream_write_single(
                return -1;
        }
 
-       assert((DWORD)len == bytes_written);
+       GIT_ASSERT((DWORD)len == bytes_written);
 
        return 0;
 }
@@ -1366,7 +1423,7 @@ static int winhttp_stream_write_buffered(
                return -1;
        }
 
-       assert((DWORD)len == bytes_written);
+       GIT_ASSERT((DWORD)len == bytes_written);
 
        s->post_body_len += bytes_written;
 
@@ -1573,7 +1630,7 @@ static int winhttp_action(
                        break;
 
                default:
-                       assert(0);
+                       GIT_ASSERT(0);
        }
 
        if (!ret)
index 48468dff6a0ecbac0dd37a0195f7cd1be5dad0f5..b1df79eacfcf9e417027f144d9637407b9b96429 100644 (file)
@@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
 static int valid_entry_name(git_repository *repo, const char *filename)
 {
        return *filename != '\0' &&
-               git_path_isvalid(repo, filename, 0,
+               git_path_validate(repo, filename, 0,
                GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH);
 }
 
@@ -228,7 +228,7 @@ int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source)
 {
        git_tree_entry *cpy;
 
-       assert(source);
+       GIT_ASSERT_ARG(source);
 
        cpy = alloc_entry(source->filename, source->filename_len, source->oid);
        if (cpy == NULL)
@@ -261,19 +261,19 @@ git_filemode_t git_tree_entry_filemode_raw(const git_tree_entry *entry)
 
 const char *git_tree_entry_name(const git_tree_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return entry->filename;
 }
 
 const git_oid *git_tree_entry_id(const git_tree_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL);
        return entry->oid;
 }
 
 git_object_t git_tree_entry_type(const git_tree_entry *entry)
 {
-       assert(entry);
+       GIT_ASSERT_ARG_WITH_RETVAL(entry, GIT_OBJECT_INVALID);
 
        if (S_ISGITLINK(entry->attr))
                return GIT_OBJECT_COMMIT;
@@ -288,7 +288,9 @@ int git_tree_entry_to_object(
        git_repository *repo,
        const git_tree_entry *entry)
 {
-       assert(entry && object_out);
+       GIT_ASSERT_ARG(entry);
+       GIT_ASSERT_ARG(object_out);
+
        return git_object_lookup(object_out, repo, entry->oid, GIT_OBJECT_ANY);
 }
 
@@ -306,7 +308,8 @@ static const git_tree_entry *entry_fromname(
 const git_tree_entry *git_tree_entry_byname(
        const git_tree *tree, const char *filename)
 {
-       assert(tree && filename);
+       GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL);
 
        return entry_fromname(tree, filename, strlen(filename));
 }
@@ -314,7 +317,7 @@ const git_tree_entry *git_tree_entry_byname(
 const git_tree_entry *git_tree_entry_byindex(
        const git_tree *tree, size_t idx)
 {
-       assert(tree);
+       GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL);
        return git_array_get(tree->entries, idx);
 }
 
@@ -324,7 +327,7 @@ const git_tree_entry *git_tree_entry_byid(
        size_t i;
        const git_tree_entry *e;
 
-       assert(tree);
+       GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL);
 
        git_array_foreach(tree->entries, i, e) {
                if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0)
@@ -336,13 +339,13 @@ const git_tree_entry *git_tree_entry_byid(
 
 size_t git_tree_entrycount(const git_tree *tree)
 {
-       assert(tree);
+       GIT_ASSERT_ARG_WITH_RETVAL(tree, 0);
        return tree->entries.size;
 }
 
 size_t git_treebuilder_entrycount(git_treebuilder *bld)
 {
-       assert(bld);
+       GIT_ASSERT_ARG_WITH_RETVAL(bld, 0);
 
        return git_strmap_size(bld->map);
 }
@@ -489,6 +492,56 @@ static int check_entry(git_repository *repo, const char *filename, const git_oid
        return 0;
 }
 
+static int git_treebuilder__write_with_buffer(
+       git_oid *oid,
+       git_treebuilder *bld,
+       git_buf *buf)
+{
+       int error = 0;
+       size_t i, entrycount;
+       git_odb *odb;
+       git_tree_entry *entry;
+       git_vector entries = GIT_VECTOR_INIT;
+
+       git_buf_clear(buf);
+
+       entrycount = git_strmap_size(bld->map);
+       if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0)
+               goto out;
+
+       if (buf->asize == 0 &&
+           (error = git_buf_grow(buf, entrycount * 72)) < 0)
+               goto out;
+
+       git_strmap_foreach_value(bld->map, entry, {
+               if ((error = git_vector_insert(&entries, entry)) < 0)
+                       goto out;
+       });
+
+       git_vector_sort(&entries);
+
+       for (i = 0; i < entries.length && !error; ++i) {
+               entry = git_vector_get(&entries, i);
+
+               git_buf_printf(buf, "%o ", entry->attr);
+               git_buf_put(buf, entry->filename, entry->filename_len + 1);
+               git_buf_put(buf, (char *)entry->oid->id, GIT_OID_RAWSZ);
+
+               if (git_buf_oom(buf)) {
+                       error = -1;
+                       goto out;
+               }
+       }
+
+       if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0)
+               error = git_odb_write(oid, odb, buf->ptr, buf->size, GIT_OBJECT_TREE);
+
+out:
+       git_vector_free(&entries);
+
+       return error;
+}
+
 static int append_entry(
        git_treebuilder *bld,
        const char *filename,
@@ -607,7 +660,7 @@ static int write_tree(
                }
        }
 
-       if (git_treebuilder_write_with_buffer(oid, bld, shared_buf) < 0)
+       if (git_treebuilder__write_with_buffer(oid, bld, shared_buf) < 0)
                goto on_error;
 
        git_treebuilder_free(bld);
@@ -626,7 +679,9 @@ int git_tree__write_index(
        git_buf shared_buf = GIT_BUF_INIT;
        bool old_ignore_case = false;
 
-       assert(oid && index && repo);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(index);
+       GIT_ASSERT_ARG(repo);
 
        if (git_index_has_conflicts(index)) {
                git_error_set(GIT_ERROR_INDEX,
@@ -680,7 +735,8 @@ int git_treebuilder_new(
        git_treebuilder *bld;
        size_t i;
 
-       assert(builder_p && repo);
+       GIT_ASSERT_ARG(builder_p);
+       GIT_ASSERT_ARG(repo);
 
        bld = git__calloc(1, sizeof(git_treebuilder));
        GIT_ERROR_CHECK_ALLOC(bld);
@@ -723,7 +779,9 @@ int git_treebuilder_insert(
        git_tree_entry *entry;
        int error;
 
-       assert(bld && id && filename);
+       GIT_ASSERT_ARG(bld);
+       GIT_ASSERT_ARG(id);
+       GIT_ASSERT_ARG(filename);
 
        if ((error = check_entry(bld->repo, filename, id, filemode)) < 0)
                return error;
@@ -751,7 +809,9 @@ int git_treebuilder_insert(
 
 static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename)
 {
-       assert(bld && filename);
+       GIT_ASSERT_ARG_WITH_RETVAL(bld, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL);
+
        return git_strmap_get(bld->map, filename);
 }
 
@@ -775,63 +835,10 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
 
 int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
 {
-       int error;
-       git_buf buffer = GIT_BUF_INIT;
-
-       error = git_treebuilder_write_with_buffer(oid, bld, &buffer);
-
-       git_buf_dispose(&buffer);
-       return error;
-}
-
-int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *tree)
-{
-       int error = 0;
-       size_t i, entrycount;
-       git_odb *odb;
-       git_tree_entry *entry;
-       git_vector entries = GIT_VECTOR_INIT;
-
-       assert(bld);
-       assert(tree);
-
-       git_buf_clear(tree);
-
-       entrycount = git_strmap_size(bld->map);
-       if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0)
-               goto out;
-
-       if (tree->asize == 0 &&
-           (error = git_buf_grow(tree, entrycount * 72)) < 0)
-               goto out;
-
-       git_strmap_foreach_value(bld->map, entry, {
-               if ((error = git_vector_insert(&entries, entry)) < 0)
-                       goto out;
-       });
-
-       git_vector_sort(&entries);
+       GIT_ASSERT_ARG(oid);
+       GIT_ASSERT_ARG(bld);
 
-       for (i = 0; i < entries.length && !error; ++i) {
-               entry = git_vector_get(&entries, i);
-
-               git_buf_printf(tree, "%o ", entry->attr);
-               git_buf_put(tree, entry->filename, entry->filename_len + 1);
-               git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
-
-               if (git_buf_oom(tree)) {
-                       error = -1;
-                       goto out;
-               }
-       }
-
-       if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0)
-               error = git_odb_write(oid, odb, tree->ptr, tree->size, GIT_OBJECT_TREE);
-
-out:
-       git_vector_free(&entries);
-
-       return error;
+       return git_treebuilder__write_with_buffer(oid, bld, &bld->write_cache);
 }
 
 int git_treebuilder_filter(
@@ -842,7 +849,8 @@ int git_treebuilder_filter(
        const char *filename;
        git_tree_entry *entry;
 
-       assert(bld && filter);
+       GIT_ASSERT_ARG(bld);
+       GIT_ASSERT_ARG(filter);
 
        git_strmap_foreach(bld->map, filename, entry, {
                        if (filter(entry, payload)) {
@@ -858,7 +866,7 @@ int git_treebuilder_clear(git_treebuilder *bld)
 {
        git_tree_entry *e;
 
-       assert(bld);
+       GIT_ASSERT_ARG(bld);
 
        git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e));
        git_strmap_clear(bld->map);
@@ -871,6 +879,7 @@ void git_treebuilder_free(git_treebuilder *bld)
        if (bld == NULL)
                return;
 
+       git_buf_dispose(&bld->write_cache);
        git_treebuilder_clear(bld);
        git_strmap_free(bld->map);
        git__free(bld);
@@ -1174,10 +1183,10 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
 
                for (j = 0; j < steps_up; j++) {
                        tree_stack_entry *current, *popped = git_array_pop(stack);
-                       assert(popped);
+                       GIT_ASSERT(popped);
 
                        current = git_array_last(stack);
-                       assert(current);
+                       GIT_ASSERT(current);
 
                        if ((error = create_popped_tree(current, popped, &component)) < 0)
                                goto cleanup;
@@ -1242,8 +1251,9 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
                        }
                        case GIT_TREE_UPDATE_REMOVE:
                        {
+                               tree_stack_entry *last = git_array_last(stack);
                                char *basename = git_path_basename(update->path);
-                               error = git_treebuilder_remove(git_array_last(stack)->bld, basename);
+                               error = git_treebuilder_remove(last->bld, basename);
                                git__free(basename);
                                break;
                        }
@@ -1295,3 +1305,16 @@ cleanup:
        git_vector_free(&entries);
        return error;
 }
+
+/* Deprecated Functions */
+
+#ifndef GIT_DEPRECATE_HARD
+
+int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *buf)
+{
+       GIT_UNUSED(buf);
+
+       return git_treebuilder_write(oid, bld);
+}
+
+#endif
index 973ba15d0a3134d82ae0b376a6025866a36016ed..2f3027b5a273b3cb44dc9187f3e89e913af1acd3 100644 (file)
@@ -32,6 +32,7 @@ struct git_tree {
 struct git_treebuilder {
        git_repository *repo;
        git_strmap *map;
+       git_buf write_cache;
 };
 
 GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
index 8d1ed9787c00a26126f71812f66cf4494af52dea..045efad23f6d09b65988192c8ae677fa9812b1b5 100644 (file)
@@ -29,8 +29,6 @@ static int binsearch(
        int l, c, r;
        void *lx, *cx;
 
-       assert(size > 0);
-
        l = 0;
        r = (int)size - 1;
        c = r >> 1;
index 7f9076e19cfdfabb4acf9a56285f3fd729a877af..88f283ce815f00a535d7709762a0bc2db4638dd4 100644 (file)
@@ -66,8 +66,10 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset
 
 int p_munmap(git_map *map)
 {
-       assert(map != NULL);
+       GIT_ASSERT_ARG(map);
        munmap(map->data, map->len);
+       map->data = NULL;
+       map->len = 0;
 
        return 0;
 }
index b5527a4a84bfbe436a3f6ce2559cd77d0692020b..7b3325e78176dd385690fde2acad469d1e00cf05 100644 (file)
@@ -101,4 +101,7 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
 # define p_futimes futimes
 #endif
 
+#define p_pread(f, d, s, o) pread(f, d, s, o)
+#define p_pwrite(f, d, s, o) pwrite(f, d, s, o)
+
 #endif
index 233561b4e0cb80d68ea13279dd874c3495ca33fe..55f4ae227eebb12399c1cc9b2100cd96705c2a3c 100644 (file)
@@ -12,7 +12,8 @@ typedef struct {
        pthread_t thread;
 } git_thread;
 
-#define git_threads_init() (void)0
+GIT_INLINE(int) git_threads_global_init(void) { return 0; }
+
 #define git_thread_create(git_thread_ptr, start_routine, arg) \
        pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
 #define git_thread_join(git_thread_ptr, status) \
diff --git a/src/utf8.c b/src/utf8.c
new file mode 100644 (file)
index 0000000..77065cb
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "utf8.h"
+
+#include "common.h"
+
+/*
+ * git_utf8_iterate is taken from the utf8proc project,
+ * http://www.public-software-group.org/utf8proc
+ *
+ * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the ""Software""),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+static const uint8_t utf8proc_utf8class[256] = {
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int utf8_charlen(const uint8_t *str, size_t str_len)
+{
+       uint8_t length;
+       size_t i;
+
+       length = utf8proc_utf8class[str[0]];
+       if (!length)
+               return -1;
+
+       if (str_len > 0 && length > str_len)
+               return -1;
+
+       for (i = 1; i < length; i++) {
+               if ((str[i] & 0xC0) != 0x80)
+                       return -1;
+       }
+
+       return (int)length;
+}
+
+int git_utf8_iterate(uint32_t *out, const char *_str, size_t str_len)
+{
+       const uint8_t *str = (const uint8_t *)_str;
+       uint32_t uc = 0;
+       int length;
+
+       *out = 0;
+
+       if ((length = utf8_charlen(str, str_len)) < 0)
+               return -1;
+
+       switch (length) {
+               case 1:
+                       uc = str[0];
+                       break;
+               case 2:
+                       uc = ((str[0] & 0x1F) <<  6) + (str[1] & 0x3F);
+                       if (uc < 0x80) uc = -1;
+                       break;
+               case 3:
+                       uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) <<  6)
+                               + (str[2] & 0x3F);
+                       if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
+                                       (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
+                       break;
+               case 4:
+                       uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
+                               + ((str[2] & 0x3F) <<  6) + (str[3] & 0x3F);
+                       if (uc < 0x10000 || uc >= 0x110000) uc = -1;
+                       break;
+               default:
+                       return -1;
+       }
+
+       if ((uc & 0xFFFF) >= 0xFFFE)
+               return -1;
+
+       *out = uc;
+       return length;
+}
+
+size_t git_utf8_char_length(const char *_str, size_t str_len)
+{
+       const uint8_t *str = (const uint8_t *)_str;
+       size_t offset = 0, count = 0;
+
+       while (offset < str_len) {
+               int length = utf8_charlen(str + offset, str_len - offset);
+
+               if (length < 0)
+                       length = 1;
+
+               offset += length;
+               count++;
+       }
+
+       return count;
+}
+
+size_t git_utf8_valid_buf_length(const char *_str, size_t str_len)
+{
+       const uint8_t *str = (const uint8_t *)_str;
+       size_t offset = 0;
+
+       while (offset < str_len) {
+               int length = utf8_charlen(str + offset, str_len - offset);
+
+               if (length < 0)
+                       break;
+
+               offset += length;
+       }
+
+       return offset;
+}
diff --git a/src/utf8.h b/src/utf8.h
new file mode 100644 (file)
index 0000000..dff91b2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_utf8_h__
+#define INCLUDE_utf8_h__
+
+#include "common.h"
+
+/*
+ * Iterate through an UTF-8 string, yielding one codepoint at a time.
+ *
+ * @param out pointer where to store the current codepoint
+ * @param str current position in the string
+ * @param str_len size left in the string
+ * @return length in bytes of the read codepoint; -1 if the codepoint was invalid
+ */
+extern int git_utf8_iterate(uint32_t *out, const char *str, size_t str_len);
+
+/**
+ * Returns the number of characters in the given string.
+ *
+ * This function will count invalid codepoints; if any given byte is
+ * not part of a valid UTF-8 codepoint, then it will be counted toward
+ * the length in characters.
+ *
+ * In other words:
+ *   0x24 (U+0024 "$") has length 1
+ *   0xc2 0xa2 (U+00A2 "¢") has length 1
+ *   0x24 0xc2 0xa2 (U+0024 U+00A2 "$¢") has length 2
+ *   0xf0 0x90 0x8d 0x88 (U+10348 "𐍈") has length 1
+ *   0x24 0xc0 0xc1 0x34 (U+0024 <invalid> <invalid> "4) has length 4
+ *
+ * @param str string to scan
+ * @param str_len size of the string
+ * @return length in characters of the string
+ */
+extern size_t git_utf8_char_length(const char *str, size_t str_len);
+
+/**
+ * Iterate through an UTF-8 string and stops after finding any invalid UTF-8
+ * codepoints.
+ *
+ * @param str string to scan
+ * @param str_len size of the string
+ * @return length in bytes of the string that contains valid data
+ */
+extern size_t git_utf8_valid_buf_length(const char *str, size_t str_len);
+
+#endif
index 2efb212bc79367341cebc730c9f0c656e675d2a7..9b0c45ce82573a759d6f9c46e8eed0f096d99aff 100644 (file)
 # include "win32/utf-conv.h"
 # include "win32/w32_buffer.h"
 
+# ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+
 # ifdef HAVE_QSORT_S
 #  include <search.h>
 # endif
 # include <Shlwapi.h>
 #endif
 
+#if defined(hpux) || defined(__hpux) || defined(_hpux)
+# include <sys/pstat.h>
+#endif
+
 int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
 {
        const char *p;
-       int64_t n, nn;
-       int c, ovfl, v, neg, ndig;
+       int64_t n, nn, v;
+       int c, ovfl, neg, ndig;
 
        p = nptr;
        neg = 0;
@@ -101,19 +110,11 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha
                if (v >= base)
                        break;
                v = neg ? -v : v;
-               if (n > INT64_MAX / base || n < INT64_MIN / base) {
-                       ovfl = 1;
-                       /* Keep on iterating until the end of this number */
-                       continue;
-               }
-               nn = n * base;
-               if ((v > 0 && nn > INT64_MAX - v) ||
-                   (v < 0 && nn < INT64_MIN - v)) {
+               if (git__multiply_int64_overflow(&nn, n, base) || git__add_int64_overflow(&n, nn, v)) {
                        ovfl = 1;
                        /* Keep on iterating until the end of this number */
                        continue;
                }
-               n = nn + v;
        }
 
 Return:
@@ -678,7 +679,7 @@ typedef struct {
        void *payload;
 } git__qsort_r_glue;
 
-static int GIT_STDLIB_CALL git__qsort_r_glue_cmp(
+static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp(
        void *payload, const void *a, const void *b)
 {
        git__qsort_r_glue *glue = payload;
@@ -733,123 +734,6 @@ void git__qsort_r(
 #endif
 }
 
-/*
- * git__utf8_iterate is taken from the utf8proc project,
- * http://www.public-software-group.org/utf8proc
- *
- * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the ""Software""),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-static const int8_t utf8proc_utf8class[256] = {
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-       4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static int util_utf8_charlen(const uint8_t *str, size_t str_len)
-{
-       size_t length, i;
-
-       length = utf8proc_utf8class[str[0]];
-       if (!length)
-               return -1;
-
-       if (str_len > 0 && length > str_len)
-               return -1;
-
-       for (i = 1; i < length; i++) {
-               if ((str[i] & 0xC0) != 0x80)
-                       return -1;
-       }
-
-       return (int)length;
-}
-
-int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst)
-{
-       int length;
-       int32_t uc = -1;
-
-       *dst = -1;
-       length = util_utf8_charlen(str, str_len);
-       if (length < 0)
-               return -1;
-
-       switch (length) {
-               case 1:
-                       uc = str[0];
-                       break;
-               case 2:
-                       uc = ((str[0] & 0x1F) <<  6) + (str[1] & 0x3F);
-                       if (uc < 0x80) uc = -1;
-                       break;
-               case 3:
-                       uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) <<  6)
-                               + (str[2] & 0x3F);
-                       if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
-                                       (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
-                       break;
-               case 4:
-                       uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
-                               + ((str[2] & 0x3F) <<  6) + (str[3] & 0x3F);
-                       if (uc < 0x10000 || uc >= 0x110000) uc = -1;
-                       break;
-       }
-
-       if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE))
-               return -1;
-
-       *dst = uc;
-       return length;
-}
-
-size_t git__utf8_valid_buf_length(const uint8_t *str, size_t str_len)
-{
-       size_t offset = 0;
-
-       while (offset < str_len) {
-               int length = util_utf8_charlen(str + offset, str_len - offset);
-
-               if (length < 0)
-                       break;
-
-               offset += length;
-       }
-
-       return offset;
-}
-
 #ifdef GIT_WIN32
 int git__getenv(git_buf *out, const char *name)
 {
@@ -871,7 +755,7 @@ int git__getenv(git_buf *out, const char *name)
 
        if (value_len)
                error = git_buf_put_w(out, wide_value, value_len);
-       else if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+       else if (GetLastError() == ERROR_SUCCESS || GetLastError() == ERROR_ENVVAR_NOT_FOUND)
                error = GIT_ENOTFOUND;
        else
                git_error_set(GIT_ERROR_OS, "could not read environment variable '%s'", name);
@@ -893,3 +777,43 @@ int git__getenv(git_buf *out, const char *name)
        return git_buf_puts(out, val);
 }
 #endif
+
+/*
+ * By doing this in two steps we can at least get
+ * the function to be somewhat coherent, even
+ * with this disgusting nest of #ifdefs.
+ */
+#ifndef _SC_NPROCESSORS_ONLN
+#      ifdef _SC_NPROC_ONLN
+#              define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
+#      elif defined _SC_CRAY_NCPU
+#              define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
+#      endif
+#endif
+
+int git__online_cpus(void)
+{
+#ifdef _SC_NPROCESSORS_ONLN
+       long ncpus;
+#endif
+
+#ifdef _WIN32
+       SYSTEM_INFO info;
+       GetSystemInfo(&info);
+
+       if ((int)info.dwNumberOfProcessors > 0)
+               return (int)info.dwNumberOfProcessors;
+#elif defined(hpux) || defined(__hpux) || defined(_hpux)
+       struct pst_dynamic psd;
+
+       if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
+               return (int)psd.psd_proc_cnt;
+#endif
+
+#ifdef _SC_NPROCESSORS_ONLN
+       if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
+               return (int)ncpus;
+#endif
+
+       return 1;
+}
index f49989f7ed21129d048aa91cc689fb03af4685e1..e8074fcb9da2da3b22890a991943dfdbb04627f5 100644 (file)
 #include "buffer.h"
 #include "common.h"
 #include "strnlen.h"
-#include "thread-utils.h"
+#include "thread.h"
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 #define bitsizeof(x) (CHAR_BIT * sizeof(x))
-#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
+#define MSB(x, bits) ((x) & (~UINT64_C(0) << (bitsizeof(x) - (bits))))
 #ifndef min
 # define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
@@ -34,7 +34,7 @@
 # define GIT_CONTAINER_OF(ptr, type, member) \
        __builtin_choose_expr( \
            __builtin_offsetof(type, member) == 0 && \
-           __builtin_types_compatible_p(typeof(&((type *) 0)->member), typeof(ptr)), \
+           __builtin_types_compatible_p(__typeof__(&((type *) 0)->member), __typeof__(ptr)), \
                ((type *) (ptr)), \
                (void)0)
 #else
@@ -168,30 +168,41 @@ extern int git__strncasecmp(const char *a, const char *b, size_t sz);
 
 extern int git__strcasesort_cmp(const char *a, const char *b);
 
+/*
+ * Compare some NUL-terminated `a` to a possibly non-NUL terminated
+ * `b` of length `b_len`; like `strncmp` but ensuring that
+ * `strlen(a) == b_len` as well.
+ */
+GIT_INLINE(int) git__strlcmp(const char *a, const char *b, size_t b_len)
+{
+       int cmp = strncmp(a, b, b_len);
+       return cmp ? cmp : (int)a[b_len];
+}
+
 typedef struct {
-       git_atomic refcount;
+       git_atomic32 refcount;
        void *owner;
 } git_refcount;
 
 typedef void (*git_refcount_freeptr)(void *r);
 
 #define GIT_REFCOUNT_INC(r) { \
-       git_atomic_inc(&(r)->rc.refcount);      \
+       git_atomic32_inc(&(r)->rc.refcount);    \
 }
 
 #define GIT_REFCOUNT_DEC(_r, do_free) { \
        git_refcount *r = &(_r)->rc; \
-       int val = git_atomic_dec(&r->refcount); \
+       int val = git_atomic32_dec(&r->refcount); \
        if (val <= 0 && r->owner == NULL) { do_free(_r); } \
 }
 
 #define GIT_REFCOUNT_OWN(r, o) { \
-       (void)git__swap((r)->rc.owner, o); \
+       (void)git_atomic_swap((r)->rc.owner, o); \
 }
 
-#define GIT_REFCOUNT_OWNER(r) git__load((r)->rc.owner)
+#define GIT_REFCOUNT_OWNER(r) git_atomic_load((r)->rc.owner)
 
-#define GIT_REFCOUNT_VAL(r) git_atomic_get((r)->rc.refcount)
+#define GIT_REFCOUNT_VAL(r) git_atomic32_get((r)->rc.refcount)
 
 
 static signed char from_hex[] = {
@@ -316,27 +327,6 @@ extern int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date);
  */
 extern size_t git__unescape(char *str);
 
-/*
- * Iterate through an UTF-8 string, yielding one
- * codepoint at a time.
- *
- * @param str current position in the string
- * @param str_len size left in the string; -1 if the string is NULL-terminated
- * @param dst pointer where to store the current codepoint
- * @return length in bytes of the read codepoint; -1 if the codepoint was invalid
- */
-extern int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst);
-
-/*
- * Iterate through an UTF-8 string and stops after finding any invalid UTF-8
- * codepoints.
- *
- * @param str string to scan
- * @param str_len size of the string
- * @return length in bytes of the string that contains valid data
- */
-extern size_t git__utf8_valid_buf_length(const uint8_t *str, size_t str_len);
-
 /*
  * Safely zero-out memory, making sure that the compiler
  * doesn't optimize away the operation.
@@ -380,7 +370,7 @@ GIT_INLINE(double) git__timer(void)
    return (double)time * scaling_factor / 1.0E9;
 }
 
-#elif defined(AMIGA)
+#elif defined(__amigaos4__)
 
 #include <proto/timer.h>
 
@@ -397,23 +387,27 @@ GIT_INLINE(double) git__timer(void)
 
 GIT_INLINE(double) git__timer(void)
 {
-       struct timespec tp;
+       struct timeval tv;
 
-       if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
+#ifdef CLOCK_MONOTONIC
+       struct timespec tp;
+       if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
                return (double) tp.tv_sec + (double) tp.tv_nsec / 1.0E9;
-       } else {
-               /* Fall back to using gettimeofday */
-               struct timeval tv;
-               struct timezone tz;
-               gettimeofday(&tv, &tz);
-               return (double)tv.tv_sec + (double)tv.tv_usec / 1.0E6;
-       }
+#endif
+
+       /* Fall back to using gettimeofday */
+       gettimeofday(&tv, NULL);
+       return (double)tv.tv_sec + (double)tv.tv_usec / 1.0E6;
 }
 
 #endif
 
 extern int git__getenv(git_buf *out, const char *name);
 
+extern int git__online_cpus(void);
+
+GIT_INLINE(int) git__noop(void) { return 0; }
+
 #include "alloc.h"
 
 #endif
index b51e7644b56269bfea532d06628808d8c5b4ffe7..4a4bc8c0e448ea2d596923d4fa180aadbff20b35 100644 (file)
@@ -53,7 +53,8 @@ int git_vector_size_hint(git_vector *v, size_t size_hint)
 
 int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
 {
-       assert(v && src);
+       GIT_ASSERT_ARG(v);
+       GIT_ASSERT_ARG(src);
 
        v->_alloc_size = 0;
        v->contents = NULL;
@@ -77,7 +78,8 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
 
 void git_vector_free(git_vector *v)
 {
-       assert(v);
+       if (!v)
+               return;
 
        git__free(v->contents);
        v->contents = NULL;
@@ -90,7 +92,8 @@ void git_vector_free_deep(git_vector *v)
 {
        size_t i;
 
-       assert(v);
+       if (!v)
+               return;
 
        for (i = 0; i < v->length; ++i) {
                git__free(v->contents[i]);
@@ -102,7 +105,7 @@ void git_vector_free_deep(git_vector *v)
 
 int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
 {
-       assert(v);
+       GIT_ASSERT_ARG(v);
 
        v->_alloc_size = 0;
        v->_cmp = cmp;
@@ -131,7 +134,7 @@ void **git_vector_detach(size_t *size, size_t *asize, git_vector *v)
 
 int git_vector_insert(git_vector *v, void *element)
 {
-       assert(v);
+       GIT_ASSERT_ARG(v);
 
        if (v->length >= v->_alloc_size &&
                resize_vector(v, compute_new_size(v)) < 0)
@@ -150,7 +153,8 @@ int git_vector_insert_sorted(
        int result;
        size_t pos;
 
-       assert(v && v->_cmp);
+       GIT_ASSERT_ARG(v);
+       GIT_ASSERT(v->_cmp);
 
        if (!git_vector_is_sorted(v))
                git_vector_sort(v);
@@ -180,8 +184,6 @@ int git_vector_insert_sorted(
 
 void git_vector_sort(git_vector *v)
 {
-       assert(v);
-
        if (git_vector_is_sorted(v) || !v->_cmp)
                return;
 
@@ -196,7 +198,9 @@ int git_vector_bsearch2(
        git_vector_cmp key_lookup,
        const void *key)
 {
-       assert(v && key && key_lookup);
+       GIT_ASSERT_ARG(v);
+       GIT_ASSERT_ARG(key);
+       GIT_ASSERT(key_lookup);
 
        /* need comparison function to sort the vector */
        if (!v->_cmp)
@@ -212,7 +216,9 @@ int git_vector_search2(
 {
        size_t i;
 
-       assert(v && key && key_lookup);
+       GIT_ASSERT_ARG(v);
+       GIT_ASSERT_ARG(key);
+       GIT_ASSERT(key_lookup);
 
        for (i = 0; i < v->length; ++i) {
                if (key_lookup(key, v->contents[i]) == 0) {
@@ -240,7 +246,7 @@ int git_vector_remove(git_vector *v, size_t idx)
 {
        size_t shift_count;
 
-       assert(v);
+       GIT_ASSERT_ARG(v);
 
        if (idx >= v->length)
                return GIT_ENOTFOUND;
@@ -303,7 +309,6 @@ void git_vector_remove_matching(
 
 void git_vector_clear(git_vector *v)
 {
-       assert(v);
        v->length = 0;
        git_vector_set_sorted(v, 1);
 }
@@ -312,8 +317,6 @@ void git_vector_swap(git_vector *a, git_vector *b)
 {
        git_vector t;
 
-       assert(a && b);
-
        if (a != b) {
                memcpy(&t, a, sizeof(t));
                memcpy(a, b, sizeof(t));
@@ -340,7 +343,8 @@ int git_vector_insert_null(git_vector *v, size_t idx, size_t insert_len)
 {
        size_t new_length;
 
-       assert(insert_len > 0 && idx <= v->length);
+       GIT_ASSERT_ARG(insert_len > 0);
+       GIT_ASSERT_ARG(idx <= v->length);
 
        GIT_ERROR_CHECK_ALLOC_ADD(&new_length, v->length, insert_len);
 
@@ -359,13 +363,13 @@ int git_vector_remove_range(git_vector *v, size_t idx, size_t remove_len)
 {
        size_t new_length = v->length - remove_len;
        size_t end_idx = 0;
-       
-       assert(remove_len > 0);
+
+       GIT_ASSERT_ARG(remove_len > 0);
 
        if (git__add_sizet_overflow(&end_idx, idx, remove_len))
-               assert(0);
+               GIT_ASSERT(0);
 
-       assert(end_idx <= v->length);
+       GIT_ASSERT(end_idx <= v->length);
 
        if (end_idx < v->length)
                memmove(&v->contents[idx], &v->contents[end_idx],
index cc4c314d5a3206f813a3d556392e2c90bc7f656e..3dcec3d1319b78f6fcb63b768edfa0f728c327c2 100644 (file)
@@ -26,11 +26,13 @@ typedef struct git_vector {
 
 #define GIT_VECTOR_INIT {0}
 
-int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp);
+GIT_WARN_UNUSED_RESULT int git_vector_init(
+       git_vector *v, size_t initial_size, git_vector_cmp cmp);
 void git_vector_free(git_vector *v);
 void git_vector_free_deep(git_vector *v); /* free each entry and self */
 void git_vector_clear(git_vector *v);
-int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp);
+GIT_WARN_UNUSED_RESULT int git_vector_dup(
+       git_vector *v, const git_vector *src, git_vector_cmp cmp);
 void git_vector_swap(git_vector *a, git_vector *b);
 int git_vector_size_hint(git_vector *v, size_t size_hint);
 
index 7f077e154ffba6a9f821ca2f19b53a42701fa4dd..40d2d518a182e6df80df65841aebded44e8a13d3 100644 (file)
@@ -49,11 +49,13 @@ static int win32_path_to_8(git_buf *dest, const wchar_t *src)
        return git_buf_sets(dest, utf8_path);
 }
 
-static wchar_twin32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen)
+static wchar_t *win32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen)
 {
        wchar_t term, *base = path;
 
-       assert(path && buf && buflen);
+       GIT_ASSERT_ARG_WITH_RETVAL(path, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(buf, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(buflen, NULL);
 
        term = (*path == L'"') ? *path++ : L';';
 
@@ -109,7 +111,7 @@ static int win32_find_git_in_registry(
        HKEY hKey;
        int error = GIT_ENOTFOUND;
 
-       assert(buf);
+       GIT_ASSERT_ARG(buf);
 
        if (!RegOpenKeyExW(hive, key, 0, KEY_READ, &hKey)) {
                DWORD dwType, cbData;
index e2ce737debdf30b20e1dfdd366afe90e6c68758b..2aabc9b153d4952c466029a26b91850ed96bd1c9 100644 (file)
@@ -117,7 +117,7 @@ int p_munmap(git_map *map)
 {
        int error = 0;
 
-       assert(map != NULL);
+       GIT_ASSERT_ARG(map);
 
        if (map->data) {
                if (!UnmapViewOfFile(map->data)) {
index 4cf471f1d3c394388d088e0c08b08802c48c6260..03f9f36dc9270044a1a0618c70319bda1ce84461 100644 (file)
@@ -23,6 +23,14 @@ typedef SSIZE_T ssize_t;
 
 #endif
 
-#define GIT_STDLIB_CALL __cdecl
+/*
+ * Offer GIT_LIBGIT2_CALL for our calling conventions (__cdecl, always).
+ * This is useful for providing callbacks to userspace code.
+ *
+ * Offer GIT_SYSTEM_CALL for the system calling conventions (__stdcall on
+ * Win32).  Useful for providing callbacks to system libraries.
+ */
+#define GIT_LIBGIT2_CALL __cdecl
+#define GIT_SYSTEM_CALL NTAPI
 
 #endif
index 9faddcf3bfe7035eb3d7fe8ebbedec038ac321fc..e6640c85ed4ae499992509ba1bf47e7991034368 100644 (file)
@@ -170,7 +170,7 @@ static int win32_path_cwd(wchar_t *out, size_t len)
                 * '\'s, but we we add a 'UNC' specifier to the path, plus
                 * a trailing directory separator, plus a NUL.
                 */
-               if (cwd_len > MAX_PATH - 4) {
+               if (cwd_len > GIT_WIN_PATH_MAX - 4) {
                        errno = ENAMETOOLONG;
                        return -1;
                }
@@ -187,7 +187,7 @@ static int win32_path_cwd(wchar_t *out, size_t len)
         * working directory.  (One character for the directory separator,
         * one for the null.
         */
-       else if (cwd_len > MAX_PATH - 2) {
+       else if (cwd_len > GIT_WIN_PATH_MAX - 2) {
                errno = ENAMETOOLONG;
                return -1;
        }
@@ -205,13 +205,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
 
        /* See if this is an absolute path (beginning with a drive letter) */
        if (git_path_is_absolute(src)) {
-               if (git__utf8_to_16(dest, MAX_PATH, src) < 0)
+               if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0)
                        goto on_error;
        }
        /* File-prefixed NT-style paths beginning with \\?\ */
        else if (path__is_nt_namespace(src)) {
                /* Skip the NT prefix, the destination already contains it */
-               if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0)
+               if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0)
                        goto on_error;
        }
        /* UNC paths */
@@ -220,12 +220,12 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
                dest += 4;
 
                /* Skip the leading "\\" */
-               if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0)
+               if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0)
                        goto on_error;
        }
        /* Absolute paths omitting the drive letter */
        else if (path__startswith_slash(src)) {
-               if (path__cwd(dest, MAX_PATH) < 0)
+               if (path__cwd(dest, GIT_WIN_PATH_MAX) < 0)
                        goto on_error;
 
                if (!git_path_is_absolute(dest)) {
@@ -234,19 +234,19 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
                }
 
                /* Skip the drive letter specification ("C:") */
-               if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0)
+               if (git__utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0)
                        goto on_error;
        }
        /* Relative paths */
        else {
                int cwd_len;
 
-               if ((cwd_len = win32_path_cwd(dest, MAX_PATH)) < 0)
+               if ((cwd_len = win32_path_cwd(dest, GIT_WIN_PATH_MAX)) < 0)
                        goto on_error;
 
                dest[cwd_len++] = L'\\';
 
-               if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0)
+               if (git__utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0)
                        goto on_error;
        }
 
@@ -273,7 +273,7 @@ int git_win32_path_relative_from_utf8(git_win32_path out, const char *src)
                return git_win32_path_from_utf8(out, src);
        }
 
-       if ((len = git__utf8_to_16(dest, MAX_PATH, src)) < 0)
+       if ((len = git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0)
                return -1;
 
        for (p = dest; p < (dest + len); p++) {
@@ -381,14 +381,14 @@ int git_win32_path_readlink_w(git_win32_path dest, const git_win32_path path)
 
        switch (reparse_buf->ReparseTag) {
        case IO_REPARSE_TAG_SYMLINK:
-               target = reparse_buf->SymbolicLinkReparseBuffer.PathBuffer +
-                       (reparse_buf->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR));
-               target_len = reparse_buf->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+               target = reparse_buf->ReparseBuffer.SymbolicLink.PathBuffer +
+                       (reparse_buf->ReparseBuffer.SymbolicLink.SubstituteNameOffset / sizeof(WCHAR));
+               target_len = reparse_buf->ReparseBuffer.SymbolicLink.SubstituteNameLength / sizeof(WCHAR);
        break;
        case IO_REPARSE_TAG_MOUNT_POINT:
-               target = reparse_buf->MountPointReparseBuffer.PathBuffer +
-                       (reparse_buf->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR));
-               target_len = reparse_buf->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+               target = reparse_buf->ReparseBuffer.MountPoint.PathBuffer +
+                       (reparse_buf->ReparseBuffer.MountPoint.SubstituteNameOffset / sizeof(WCHAR));
+               target_len = reparse_buf->ReparseBuffer.MountPoint.SubstituteNameLength / sizeof(WCHAR);
        break;
        default:
                errno = EINVAL;
@@ -492,14 +492,12 @@ size_t git_win32_path_remove_namespace(wchar_t *str, size_t len)
                prefix_len = CONST_STRLEN(unc_prefix);
        }
 
-       if (remainder) {
-               /*
-                * Sanity check that the new string isn't longer than the old one.
-                * (This could only happen due to programmer error introducing a
-                * prefix longer than the namespace it replaces.)
-                */
-               assert(len >= remainder_len + prefix_len);
-
+       /*
+        * Sanity check that the new string isn't longer than the old one.
+        * (This could only happen due to programmer error introducing a
+        * prefix longer than the namespace it replaces.)
+        */
+       if (remainder && len >= remainder_len + prefix_len) {
                if (prefix)
                        memmove(str, prefix, prefix_len * sizeof(wchar_t));
 
index dab8b96fa79d2fe28d540c7c3ec18f300af21a92..4fadf8d084820a7f721a1b09dd4431249456aff0 100644 (file)
@@ -8,7 +8,6 @@
 #define INCLUDE_win32_path_w32_h__
 
 #include "common.h"
-#include "vector.h"
 
 /**
  * Create a Win32 path (in UCS-2 format) from a UTF-8 string.  If the given
index f115088b435f178d0870adf44025ec9f54a2a4af..87c6b436ae7589d8a6dfe705cc76a7e432a83bfe 100644 (file)
@@ -23,7 +23,7 @@ typedef SOCKET GIT_SOCKET;
 
 extern int p_fstat(int fd, struct stat *buf);
 extern int p_lstat(const char *file_name, struct stat *buf);
-extern int p_stat(const charpath, struct stat *buf);
+extern int p_stat(const char *path, struct stat *buf);
 
 extern int p_utimes(const char *filename, const struct p_timeval times[2]);
 extern int p_futimes(int fd, const struct p_timeval times[2]);
@@ -38,15 +38,15 @@ extern char *p_realpath(const char *orig_path, char *buffer);
 
 extern int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags);
 extern int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags);
-extern int p_inet_pton(int af, const charsrc, void* dst);
+extern int p_inet_pton(int af, const char *src, void* dst);
 
 extern int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr);
 extern int p_snprintf(char *buffer, size_t count, const char *format, ...) GIT_FORMAT_PRINTF(3, 4);
 extern int p_mkstemp(char *tmp_path);
-extern int p_chdir(const charpath);
-extern int p_chmod(const charpath, mode_t mode);
-extern int p_rmdir(const charpath);
-extern int p_access(const charpath, mode_t mode);
+extern int p_chdir(const char *path);
+extern int p_chmod(const char *path, mode_t mode);
+extern int p_rmdir(const char *path);
+extern int p_access(const char *path, mode_t mode);
 extern int p_ftruncate(int fd, off64_t size);
 
 /* p_lstat is almost but not quite POSIX correct.  Specifically, the use of
index cacf986e8b56755a4e7e1ac8bf73520ee28f6a12..8af07e6fa77defec3d06897c69d165e17af0f8b8 100644 (file)
@@ -14,7 +14,6 @@
 #include "utf-conv.h"
 #include "repository.h"
 #include "reparse.h"
-#include "global.h"
 #include "buffer.h"
 #include <errno.h>
 #include <io.h>
@@ -544,6 +543,13 @@ int p_open(const char *path, int flags, ...)
        mode_t mode = 0;
        struct open_opts opts = {0};
 
+       #ifdef GIT_DEBUG_STRICT_OPEN
+       if (strstr(path, "//") != NULL) {
+               errno = EACCES;
+               return -1;
+       }
+       #endif
+
        if (git_win32_path_from_utf8(wpath, path) < 0)
                return -1;
 
@@ -642,6 +648,8 @@ int p_getcwd(char *buffer_out, size_t size)
        if (!cwd)
                return -1;
 
+       git_win32_path_remove_namespace(cwd, wcslen(cwd));
+
        /* Convert the working directory back to UTF-8 */
        if (git__utf16_to_8(buffer_out, size, cwd) < 0) {
                DWORD code = GetLastError();
@@ -654,6 +662,7 @@ int p_getcwd(char *buffer_out, size_t size)
                return -1;
        }
 
+       git_path_mkposix(buffer_out);
        return 0;
 }
 
@@ -684,7 +693,7 @@ static int getfinalpath_w(
        return (int)git_win32_path_remove_namespace(dest, dwChars);
 }
 
-static int follow_and_lstat_link(git_win32_path path, struct statbuf)
+static int follow_and_lstat_link(git_win32_path path, struct stat *buf)
 {
        git_win32_path target_w;
 
@@ -710,7 +719,7 @@ int p_fstat(int fd, struct stat *buf)
        return 0;
 }
 
-int p_stat(const char* path, struct stat* buf)
+int p_stat(const char *path, struct stat *buf)
 {
        git_win32_path path_w;
        int len;
@@ -727,7 +736,7 @@ int p_stat(const char* path, struct stat* buf)
        return 0;
 }
 
-int p_chdir(const charpath)
+int p_chdir(const char *path)
 {
        git_win32_path buf;
 
@@ -737,7 +746,7 @@ int p_chdir(const char* path)
        return _wchdir(buf);
 }
 
-int p_chmod(const charpath, mode_t mode)
+int p_chmod(const char *path, mode_t mode)
 {
        git_win32_path buf;
 
@@ -747,7 +756,7 @@ int p_chmod(const char* path, mode_t mode)
        return _wchmod(buf, mode);
 }
 
-int p_rmdir(const charpath)
+int p_rmdir(const char *path)
 {
        git_win32_path buf;
        int error;
@@ -867,7 +876,7 @@ int p_mkstemp(char *tmp_path)
        return p_open(tmp_path, O_RDWR | O_CREAT | O_EXCL, 0744); /* -V536 */
 }
 
-int p_access(const charpath, mode_t mode)
+int p_access(const char *path, mode_t mode)
 {
        git_win32_path buf;
 
@@ -982,3 +991,73 @@ int p_inet_pton(int af, const char *src, void *dst)
        errno = EINVAL;
        return -1;
 }
+
+ssize_t p_pread(int fd, void *data, size_t size, off64_t offset)
+{
+       HANDLE fh;
+       DWORD rsize = 0;
+       OVERLAPPED ov = {0};
+       LARGE_INTEGER pos = {0};
+       off64_t final_offset = 0;
+
+       /* Fail if the final offset would have overflowed to match POSIX semantics. */
+       if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
+               errno = EINVAL;
+               return -1;      
+       }
+
+       /*
+        * Truncate large writes to the maximum allowable size: the caller
+        * needs to always call this in a loop anyways.
+        */
+       if (size > INT32_MAX) {
+               size = INT32_MAX;
+       }
+
+       pos.QuadPart = offset;
+       ov.Offset = pos.LowPart;
+       ov.OffsetHigh = pos.HighPart;
+       fh = (HANDLE)_get_osfhandle(fd);
+
+       if (ReadFile(fh, data, (DWORD)size, &rsize, &ov)) {
+               return (ssize_t)rsize;
+       }
+
+       set_errno();
+       return -1;
+}
+
+ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset)
+{
+       HANDLE fh;
+       DWORD wsize = 0;
+       OVERLAPPED ov = {0};
+       LARGE_INTEGER pos = {0};
+       off64_t final_offset = 0;
+
+       /* Fail if the final offset would have overflowed to match POSIX semantics. */
+       if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
+               errno = EINVAL;
+               return -1;      
+       }
+
+       /*
+        * Truncate large writes to the maximum allowable size: the caller
+        * needs to always call this in a loop anyways.
+        */
+       if (size > INT32_MAX) {
+               size = INT32_MAX;
+       }
+
+       pos.QuadPart = offset;
+       ov.Offset = pos.LowPart;
+       ov.OffsetHigh = pos.HighPart;
+       fh = (HANDLE)_get_osfhandle(fd);
+
+       if (WriteFile(fh, data, (DWORD)size, &wsize, &ov)) {
+               return (ssize_t)wsize;
+       }
+
+       set_errno();
+       return -1;
+}
index 314383d31b39f3f788e95ca2e1f0c71acce95dcd..806b1698a093934a01f636a3207947206bca2bfc 100644 (file)
@@ -1,6 +1,5 @@
 #include "common.h"
 
-#include <assert.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
index 5f7408a1b39d86af865222e7633a4cf868d49280..23312319f68fde203ab1e056679ba25a6e10ed18 100644 (file)
@@ -26,18 +26,18 @@ typedef struct _GIT_REPARSE_DATA_BUFFER {
                        USHORT PrintNameLength;
                        ULONG  Flags;
                        WCHAR  PathBuffer[1];
-               } SymbolicLinkReparseBuffer;
+               } SymbolicLink;
                struct {
                        USHORT SubstituteNameOffset;
                        USHORT SubstituteNameLength;
                        USHORT PrintNameOffset;
                        USHORT PrintNameLength;
                        WCHAR  PathBuffer[1];
-               } MountPointReparseBuffer;
+               } MountPoint;
                struct {
                        UCHAR DataBuffer[1];
-               } GenericReparseBuffer;
-       };
+               } Generic;
+       } ReparseBuffer;
 } GIT_REPARSE_DATA_BUFFER;
 
 #define REPARSE_DATA_HEADER_SIZE                       8
index 42dba7f9740990d9be033874597032941d47a4a7..f5cacd320d89008b26bfe18b93cdf6cbfceb2c2f 100644 (file)
@@ -6,8 +6,7 @@
  */
 
 #include "thread.h"
-
-#include "../global.h"
+#include "runtime.h"
 
 #define CLEAN_THREAD_EXIT 0x6F012842
 
@@ -19,6 +18,8 @@ static win32_srwlock_fn win32_srwlock_release_shared;
 static win32_srwlock_fn win32_srwlock_acquire_exclusive;
 static win32_srwlock_fn win32_srwlock_release_exclusive;
 
+static DWORD fls_index;
+
 /* The thread procedure stub used to invoke the caller's procedure
  * and capture the return value for later collection. Windows will
  * only hold a DWORD, but we need to be able to store an entire
@@ -28,14 +29,19 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
        git_thread *thread = lpParameter;
 
        /* Set the current thread for `git_thread_exit` */
-       GIT_GLOBAL->current_thread = thread;
+       FlsSetValue(fls_index, thread);
 
        thread->result = thread->proc(thread->param);
 
        return CLEAN_THREAD_EXIT;
 }
 
-int git_threads_init(void)
+static void git_threads_global_shutdown(void)
+{
+       FlsFree(fls_index);
+}
+
+int git_threads_global_init(void)
 {
        HMODULE hModule = GetModuleHandleW(L"kernel32");
 
@@ -52,7 +58,10 @@ int git_threads_init(void)
                        GetProcAddress(hModule, "ReleaseSRWLockExclusive");
        }
 
-       return 0;
+       if ((fls_index = FlsAlloc(NULL)) == FLS_OUT_OF_INDEXES)
+               return -1;
+
+       return git_runtime_shutdown_register(git_threads_global_shutdown);
 }
 
 int git_thread_create(
@@ -85,10 +94,7 @@ int git_thread_join(
 
        /* Check for the thread having exited uncleanly. If exit was unclean,
         * then we don't have a return value to give back to the caller. */
-       if (exit != CLEAN_THREAD_EXIT) {
-               assert(false);
-               thread->result = NULL;
-       }
+       GIT_ASSERT(exit == CLEAN_THREAD_EXIT);
 
        if (value_ptr)
                *value_ptr = thread->result;
@@ -99,8 +105,11 @@ int git_thread_join(
 
 void git_thread_exit(void *value)
 {
-       assert(GIT_GLOBAL->current_thread);
-       GIT_GLOBAL->current_thread->result = value;
+       git_thread *thread = FlsGetValue(fls_index);
+
+       if (thread)
+               thread->result = value;
+
        ExitThread(CLEAN_THREAD_EXIT);
 }
 
@@ -137,7 +146,7 @@ int git_cond_init(git_cond *cond)
 {
        /* This is an auto-reset event. */
        *cond = CreateEventW(NULL, FALSE, FALSE, NULL);
-       assert(*cond);
+       GIT_ASSERT(*cond);
 
        /* If we can't create the event, claim that the reason was out-of-memory.
         * The actual reason can be fetched with GetLastError(). */
@@ -152,7 +161,7 @@ int git_cond_free(git_cond *cond)
                return EINVAL;
 
        closed = CloseHandle(*cond);
-       assert(closed);
+       GIT_ASSERT(closed);
        GIT_UNUSED(closed);
 
        *cond = NULL;
@@ -174,7 +183,7 @@ int git_cond_wait(git_cond *cond, git_mutex *mutex)
                return error;
 
        wait_result = WaitForSingleObject(*cond, INFINITE);
-       assert(WAIT_OBJECT_0 == wait_result);
+       GIT_ASSERT(WAIT_OBJECT_0 == wait_result);
        GIT_UNUSED(wait_result);
 
        return git_mutex_lock(mutex);
@@ -188,7 +197,7 @@ int git_cond_signal(git_cond *cond)
                return EINVAL;
 
        signaled = SetEvent(*cond);
-       assert(signaled);
+       GIT_ASSERT(signaled);
        GIT_UNUSED(signaled);
 
        return 0;
index 41cbf015b59335db18393eb72e4350b523bd335f..8305036b4d6fc17936936d83d5e9987717f381b0 100644 (file)
@@ -35,7 +35,7 @@ typedef struct {
        } native;
 } git_rwlock;
 
-int git_threads_init(void);
+int git_threads_global_init(void);
 
 int git_thread_create(git_thread *GIT_RESTRICT,
        void *(*) (void *),
index b78a7e6f39c6afd41db56efebdc0713af541002f..f270a1e6ac9192e204761b43e527d36eb5b963bf 100644 (file)
@@ -32,13 +32,13 @@ int git_buf_put_w(git_buf *buf, const wchar_t *string_w, size_t len_w)
                return -1;
        }
 
-       assert(string_w);
+       GIT_ASSERT(string_w);
 
        /* Measure the string necessary for conversion */
        if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string_w, (int)len_w, NULL, 0, NULL, NULL)) == 0)
                return 0;
 
-       assert(utf8_len > 0);
+       GIT_ASSERT(utf8_len > 0);
 
        GIT_ERROR_CHECK_ALLOC_ADD(&new_size, buf->size, (size_t)utf8_len);
        GIT_ERROR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
@@ -50,7 +50,7 @@ int git_buf_put_w(git_buf *buf, const wchar_t *string_w, size_t len_w)
                        CP_UTF8, WC_ERR_INVALID_CHARS, string_w, (int)len_w, &buf->ptr[buf->size], utf8_len, NULL, NULL)) == 0)
                return handle_wc_error();
 
-       assert(utf8_write_len == utf8_len);
+       GIT_ASSERT(utf8_write_len == utf8_len);
 
        buf->size += utf8_write_len;
        buf->ptr[buf->size] = '\0';
index f9e74b9476f799cec8690076b163d95934df6d20..c20b3e85e7e29869f96479005696f30afee76df6 100644 (file)
@@ -8,24 +8,33 @@
 #ifndef INCLUDE_win32_w32_common_h__
 #define INCLUDE_win32_w32_common_h__
 
+#include <git2/common.h>
+
+/*
+ * 4096 is the max allowed Git path. `MAX_PATH` (260) is the typical max allowed
+ * Windows path length, however win32 Unicode APIs generally allow up to 32,767
+ * if prefixed with "\\?\" (i.e. converted to an NT-style name).
+ */
+#define GIT_WIN_PATH_MAX GIT_PATH_MAX
+
 /*
- * Provides a large enough buffer to support Windows paths:  MAX_PATH is
- * 260, corresponding to a maximum path length of 259 characters plus a
- * NULL terminator.  Prefixing with "\\?\" adds 4 characters, but if the
- * original was a UNC path, then we turn "\\server\share" into
+ * Provides a large enough buffer to support Windows Git paths:
+ * GIT_WIN_PATH_MAX is 4096, corresponding to a maximum path length of 4095
+ * characters plus a NULL terminator.  Prefixing with "\\?\" adds 4 characters,
+ * but if the original was a UNC path, then we turn "\\server\share" into
  * "\\?\UNC\server\share".  So we replace the first two characters with
- * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
+ * 8 characters, a net gain of 6, so the maximum length is GIT_WIN_PATH_MAX+6.
  */
-#define GIT_WIN_PATH_UTF16             MAX_PATH+6
+#define GIT_WIN_PATH_UTF16             GIT_WIN_PATH_MAX+6
 
-/* Maximum size of a UTF-8 Win32 path.  We remove the "\\?\" or "\\?\UNC\"
- * prefixes for presentation, bringing us back to 259 (non-NULL)
+/* Maximum size of a UTF-8 Win32 Git path.  We remove the "\\?\" or "\\?\UNC\"
+ * prefixes for presentation, bringing us back to 4095 (non-NULL)
  * characters.  UTF-8 does have 4-byte sequences, but they are encoded in
  * UTF-16 using surrogate pairs, which takes up the space of two characters.
  * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
  * (6 bytes) than one surrogate pair (4 bytes).
  */
-#define GIT_WIN_PATH_UTF8              (259 * 3 + 1)
+#define GIT_WIN_PATH_UTF8              ((GIT_WIN_PATH_MAX - 1) * 3 + 1)
 
 /*
  * The length of a Windows "shortname", for 8.3 compatibility.
diff --git a/src/win32/w32_crtdbg_stacktrace.c b/src/win32/w32_crtdbg_stacktrace.c
deleted file mode 100644 (file)
index cdb5ac1..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "w32_crtdbg_stacktrace.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-#include "w32_stack.h"
-
-#define CRTDBG_STACKTRACE__UID_LEN (15)
-
-/**
- * The stacktrace of an allocation can be distilled
- * to a unique id based upon the stackframe pointers
- * and ignoring any size arguments. We will use these
- * UIDs as the (char const*) __FILE__ argument we
- * give to the CRT malloc routines.
- */
-typedef struct {
-       char uid[CRTDBG_STACKTRACE__UID_LEN + 1];
-} git_win32__crtdbg_stacktrace__uid;
-
-/**
- * All mallocs with the same stacktrace will be de-duped
- * and aggregated into this row.
- */
-typedef struct {
-       git_win32__crtdbg_stacktrace__uid uid; /* must be first */
-       git_win32__stack__raw_data raw_data;
-       unsigned int count_allocs; /* times this alloc signature seen since init */
-       unsigned int count_allocs_at_last_checkpoint; /* times since last mark */
-       unsigned int transient_count_leaks; /* sum of leaks */
-} git_win32__crtdbg_stacktrace__row;
-
-static CRITICAL_SECTION g_crtdbg_stacktrace_cs;
-
-/**
- * CRTDBG memory leak tracking takes a "char const * const file_name"
- * and stores the pointer in the heap data (instead of allocing a copy
- * for itself).  Normally, this is not a problem, since we usually pass
- * in __FILE__.  But I'm going to lie to it and pass in the address of
- * the UID in place of the file_name.  Also, I do not want to alloc the
- * stacktrace data (because we are called from inside our alloc routines).
- * Therefore, I'm creating a very large static pool array to store row
- * data. This also eliminates the temptation to realloc it (and move the
- * UID pointers).
- *
- * And to efficiently look for duplicates we need an index on the rows
- * so we can bsearch it.  Again, without mallocing.
- *
- * If we observe more than MY_ROW_LIMIT unique malloc signatures, we
- * fall through and use the traditional __FILE__ processing and don't
- * try to de-dup them.  If your testing hits this limit, just increase
- * it and try again.
- */
-
-#define MY_ROW_LIMIT (1024 * 1024)
-static git_win32__crtdbg_stacktrace__row  g_cs_rows[MY_ROW_LIMIT];
-static git_win32__crtdbg_stacktrace__row *g_cs_index[MY_ROW_LIMIT];
-
-static unsigned int g_cs_end = MY_ROW_LIMIT;
-static unsigned int g_cs_ins = 0; /* insertion point == unique allocs seen */
-static unsigned int g_count_total_allocs = 0; /* number of allocs seen */
-static unsigned int g_transient_count_total_leaks = 0; /* number of total leaks */
-static unsigned int g_transient_count_dedup_leaks = 0; /* number of unique leaks */
-static bool g_limit_reached = false; /* had allocs after we filled row table */
-
-static unsigned int g_checkpoint_id = 0; /* to better label leak checkpoints */
-static bool g_transient_leaks_since_mark = false; /* payload for hook */
-
-/**
- * Compare function for bsearch on g_cs_index table.
- */
-static int row_cmp(const void *v1, const void *v2)
-{
-       git_win32__stack__raw_data *d1 = (git_win32__stack__raw_data*)v1;
-       git_win32__crtdbg_stacktrace__row *r2 = (git_win32__crtdbg_stacktrace__row *)v2;
-
-       return (git_win32__stack_compare(d1, &r2->raw_data));
-}
-
-/**
- * Unique insert the new data into the row and index tables.
- * We have to sort by the stackframe data itself, not the uid.
- */
-static git_win32__crtdbg_stacktrace__row * insert_unique(
-       const git_win32__stack__raw_data *pdata)
-{
-       size_t pos;
-       if (git__bsearch(g_cs_index, g_cs_ins, pdata, row_cmp, &pos) < 0) {
-               /* Append new unique item to row table. */
-               memcpy(&g_cs_rows[g_cs_ins].raw_data, pdata, sizeof(*pdata));
-               sprintf(g_cs_rows[g_cs_ins].uid.uid, "##%08lx", g_cs_ins);
-
-               /* Insert pointer to it into the proper place in the index table. */
-               if (pos < g_cs_ins)
-                       memmove(&g_cs_index[pos+1], &g_cs_index[pos], (g_cs_ins - pos)*sizeof(g_cs_index[0]));
-               g_cs_index[pos] = &g_cs_rows[g_cs_ins];
-
-               g_cs_ins++;
-       }
-
-       g_cs_index[pos]->count_allocs++;
-
-       return g_cs_index[pos];
-}
-
-/**
- * Hook function to receive leak data from the CRT. (This includes
- * both "<file_name>:(<line_number>)" data, but also each of the
- * various headers and fields.
- *
- * Scan this for the special "##<pos>" UID forms that we substituted
- * for the "<file_name>".  Map <pos> back to the row data and
- * increment its leak count.
- *
- * See https://msdn.microsoft.com/en-us/library/74kabxyx.aspx
- *
- * We suppress the actual crtdbg output.
- */
-static int __cdecl report_hook(int nRptType, char *szMsg, int *retVal)
-{
-       static int hook_result = TRUE; /* FALSE to get stock dump; TRUE to suppress. */
-       unsigned int pos;
-
-       *retVal = 0; /* do not invoke debugger */
-
-       if ((szMsg[0] != '#') || (szMsg[1] != '#'))
-               return hook_result;
-
-       if (sscanf(&szMsg[2], "%08lx", &pos) < 1)
-               return hook_result;
-       if (pos >= g_cs_ins)
-               return hook_result;
-
-       if (g_transient_leaks_since_mark) {
-               if (g_cs_rows[pos].count_allocs == g_cs_rows[pos].count_allocs_at_last_checkpoint)
-                       return hook_result;
-       }
-
-       g_cs_rows[pos].transient_count_leaks++;
-
-       if (g_cs_rows[pos].transient_count_leaks == 1)
-               g_transient_count_dedup_leaks++;
-
-       g_transient_count_total_leaks++;
-
-       return hook_result;
-}
-
-/**
- * Write leak data to all of the various places we need.
- * We force the caller to sprintf() the message first
- * because we want to avoid fprintf() because it allocs.
- */
-static void my_output(const char *buf)
-{
-       fwrite(buf, strlen(buf), 1, stderr);
-       OutputDebugString(buf);
-}
-
-/**
- * For each row with leaks, dump a stacktrace for it.
- */
-static void dump_summary(const char *label)
-{
-       unsigned int k;
-       char buf[10 * 1024];
-
-       if (g_transient_count_total_leaks == 0)
-               return;
-
-       fflush(stdout);
-       fflush(stderr);
-       my_output("\n");
-
-       if (g_limit_reached) {
-               sprintf(buf,
-                               "LEAK SUMMARY: de-dup row table[%d] filled. Increase MY_ROW_LIMIT.\n",
-                               MY_ROW_LIMIT);
-               my_output(buf);
-       }
-
-       if (!label)
-               label = "";
-
-       if (g_transient_leaks_since_mark) {
-               sprintf(buf, "LEAK CHECKPOINT %d: leaks %d unique %d: %s\n",
-                               g_checkpoint_id, g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
-               my_output(buf);
-       } else {
-               sprintf(buf, "LEAK SUMMARY: TOTAL leaks %d de-duped %d: %s\n",
-                               g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
-               my_output(buf);
-       }
-       my_output("\n");
-
-       for (k = 0; k < g_cs_ins; k++) {
-               if (g_cs_rows[k].transient_count_leaks > 0) {
-                       sprintf(buf, "LEAK: %s leaked %d of %d times:\n",
-                                       g_cs_rows[k].uid.uid,
-                                       g_cs_rows[k].transient_count_leaks,
-                                       g_cs_rows[k].count_allocs);
-                       my_output(buf);
-
-                       if (git_win32__stack_format(
-                                       buf, sizeof(buf), &g_cs_rows[k].raw_data,
-                                       NULL, NULL) >= 0) {
-                               my_output(buf);
-                       }
-
-                       my_output("\n");
-               }
-       }
-
-       fflush(stderr);
-}
-
-void git_win32__crtdbg_stacktrace_init(void)
-{
-       InitializeCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
-
-       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
-       _CrtSetReportMode(_CRT_ERROR,  _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
-       _CrtSetReportMode(_CRT_WARN,   _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
-
-       _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
-       _CrtSetReportFile(_CRT_ERROR,  _CRTDBG_FILE_STDERR);
-       _CrtSetReportFile(_CRT_WARN,   _CRTDBG_FILE_STDERR);
-
-       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
-}
-
-int git_win32__crtdbg_stacktrace__dump(
-       git_win32__crtdbg_stacktrace_options opt,
-       const char *label)
-{
-       _CRT_REPORT_HOOK old;
-       unsigned int k;
-       int r = 0;
-
-#define IS_BIT_SET(o,b) (((o) & (b)) != 0)
-
-       bool b_set_mark         = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK);
-       bool b_leaks_since_mark = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK);
-       bool b_leaks_total      = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL);
-       bool b_quiet            = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__QUIET);
-
-       if (b_leaks_since_mark && b_leaks_total) {
-               git_error_set(GIT_ERROR_INVALID, "cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL.");
-               return GIT_ERROR;
-       }
-       if (!b_set_mark && !b_leaks_since_mark && !b_leaks_total) {
-               git_error_set(GIT_ERROR_INVALID, "nothing to do.");
-               return GIT_ERROR;
-       }
-
-       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       if (b_leaks_since_mark || b_leaks_total) {
-               /* All variables with "transient" in the name are per-dump counters
-                * and reset before each dump.  This lets us handle checkpoints.
-                */
-               g_transient_count_total_leaks = 0;
-               g_transient_count_dedup_leaks = 0;
-               for (k = 0; k < g_cs_ins; k++) {
-                       g_cs_rows[k].transient_count_leaks = 0;
-               }
-       }
-
-       g_transient_leaks_since_mark = b_leaks_since_mark;
-
-       old = _CrtSetReportHook(report_hook);
-       _CrtDumpMemoryLeaks();
-       _CrtSetReportHook(old);
-
-       if (b_leaks_since_mark || b_leaks_total) {
-               r = g_transient_count_dedup_leaks;
-
-               if (!b_quiet)
-                       dump_summary(label);
-       }
-
-       if (b_set_mark) {
-               for (k = 0; k < g_cs_ins; k++) {
-                       g_cs_rows[k].count_allocs_at_last_checkpoint = g_cs_rows[k].count_allocs;
-               }
-
-               g_checkpoint_id++;
-       }
-
-       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       return r;
-}
-
-void git_win32__crtdbg_stacktrace_cleanup(void)
-{
-       /* At shutdown/cleanup, dump cummulative leak info
-        * with everything since startup.  This might generate
-        * extra noise if the caller has been doing checkpoint
-        * dumps, but it might also eliminate some false
-        * positives for resources previously reported during
-        * checkpoints.
-        */
-       git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL,
-               "CLEANUP");
-
-       DeleteCriticalSection(&g_crtdbg_stacktrace_cs);
-}
-
-const char *git_win32__crtdbg_stacktrace(int skip, const char *file)
-{
-       git_win32__stack__raw_data new_data;
-       git_win32__crtdbg_stacktrace__row *row;
-       const char * result = file;
-
-       if (git_win32__stack_capture(&new_data, skip+1) < 0)
-               return result;
-
-       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       if (g_cs_ins < g_cs_end) {
-               row = insert_unique(&new_data);
-               result = row->uid.uid;
-       } else {
-               g_limit_reached = true;
-       }
-
-       g_count_total_allocs++;
-
-       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
-
-       return result;
-}
-
-#endif
diff --git a/src/win32/w32_crtdbg_stacktrace.h b/src/win32/w32_crtdbg_stacktrace.h
deleted file mode 100644 (file)
index d65154b..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_win32_w32_crtdbg_stacktrace_h__
-#define INCLUDE_win32_w32_crtdbg_stacktrace_h__
-
-#include "common.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-
-#include <stdlib.h>
-#include <crtdbg.h>
-
-#include "git2/errors.h"
-#include "strnlen.h"
-
-/* MSVC CRTDBG memory leak reporting.
- *
- * We DO NOT use the "_CRTDBG_MAP_ALLOC" macro described in the MSVC
- * documentation because all allocs/frees in libgit2 already go through
- * the "git__" routines defined in this file.  Simply using the normal
- * reporting mechanism causes all leaks to be attributed to a routine
- * here in util.h (ie, the actual call to calloc()) rather than the
- * caller of git__calloc().
- *
- * Therefore, we declare a set of "git__crtdbg__" routines to replace
- * the corresponding "git__" routines and re-define the "git__" symbols
- * as macros.  This allows us to get and report the file:line info of
- * the real caller.
- *
- * We DO NOT replace the "git__free" routine because it needs to remain
- * a function pointer because it is used as a function argument when
- * setting up various structure "destructors".
- *
- * We also DO NOT use the "_CRTDBG_MAP_ALLOC" macro because it causes
- * "free" to be remapped to "_free_dbg" and this causes problems for
- * structures which define a field named "free".
- *
- * Finally, CRTDBG must be explicitly enabled and configured at program
- * startup.  See tests/main.c for an example.
- */
-
-/**
- * Initialize our memory leak tracking and de-dup data structures.
- * This should ONLY be called by git_libgit2_init().
- */
-void git_win32__crtdbg_stacktrace_init(void);
-
-/**
- * Shutdown our memory leak tracking and dump summary data.
- * This should ONLY be called by git_libgit2_shutdown().
- *
- * We explicitly call _CrtDumpMemoryLeaks() during here so
- * that we can compute summary data for the leaks. We print
- * the stacktrace of each unique leak.
- *
- * This cleanup does not happen if the app calls exit()
- * without calling the libgit2 shutdown code.
- *
- * This info we print here is independent of any automatic
- * reporting during exit() caused by _CRTDBG_LEAK_CHECK_DF.
- * Set it in your app if you also want traditional reporting.
- */
-void git_win32__crtdbg_stacktrace_cleanup(void);
-
-/**
- * Checkpoint options.
- */
-typedef enum git_win32__crtdbg_stacktrace_options {
-       /**
-        * Set checkpoint marker.
-        */
-       GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK         = (1 << 0),
-
-       /**
-        * Dump leaks since last checkpoint marker.
-        * May not be combined with __LEAKS_TOTAL.
-        *
-        * Note that this may generate false positives for global TLS
-        * error state and other global caches that aren't cleaned up
-        * until the thread/process terminates.  So when using this
-        * around a region of interest, also check the final (at exit)
-        * dump before digging into leaks reported here.
-        */
-       GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK = (1 << 1),
-
-       /**
-        * Dump leaks since init.  May not be combined
-        * with __LEAKS_SINCE_MARK.
-        */
-       GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL      = (1 << 2),
-
-       /**
-        * Suppress printing during dumps.
-        * Just return leak count.
-        */
-       GIT_WIN32__CRTDBG_STACKTRACE__QUIET            = (1 << 3),
-
-} git_win32__crtdbg_stacktrace_options;
-
-/**
- * Checkpoint memory state and/or dump unique stack traces of
- * current memory leaks.
- *
- * @return number of unique leaks (relative to requested starting
- * point) or error.
- */
-GIT_EXTERN(int) git_win32__crtdbg_stacktrace__dump(
-       git_win32__crtdbg_stacktrace_options opt,
-       const char *label);
-
-/**
- * Construct stacktrace and append it to the global buffer.
- * Return pointer to start of this string.  On any error or
- * lack of buffer space, just return the given file buffer
- * so it will behave as usual.
- *
- * This should ONLY be called by our internal memory allocations
- * routines.
- */
-const char *git_win32__crtdbg_stacktrace(int skip, const char *file);
-
-#endif
-#endif
diff --git a/src/win32/w32_leakcheck.c b/src/win32/w32_leakcheck.c
new file mode 100644 (file)
index 0000000..5c8425b
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "w32_leakcheck.h"
+
+#if defined(GIT_WIN32_LEAKCHECK)
+
+#include "Windows.h"
+#include "Dbghelp.h"
+#include "win32/posix.h"
+#include "hash.h"
+#include "runtime.h"
+
+/* Stack frames (for stack tracing, below) */
+
+static bool   g_win32_stack_initialized = false;
+static HANDLE g_win32_stack_process = INVALID_HANDLE_VALUE;
+static git_win32_leakcheck_stack_aux_cb_alloc  g_aux_cb_alloc  = NULL;
+static git_win32_leakcheck_stack_aux_cb_lookup g_aux_cb_lookup = NULL;
+
+int git_win32_leakcheck_stack_set_aux_cb(
+       git_win32_leakcheck_stack_aux_cb_alloc cb_alloc,
+       git_win32_leakcheck_stack_aux_cb_lookup cb_lookup)
+{
+       g_aux_cb_alloc = cb_alloc;
+       g_aux_cb_lookup = cb_lookup;
+
+       return 0;
+}
+
+/**
+ * Load symbol table data.  This should be done in the primary
+ * thread at startup (under a lock if there are other threads
+ * active).
+ */
+void git_win32_leakcheck_stack_init(void)
+{
+       if (!g_win32_stack_initialized) {
+               g_win32_stack_process = GetCurrentProcess();
+               SymSetOptions(SYMOPT_LOAD_LINES);
+               SymInitialize(g_win32_stack_process, NULL, TRUE);
+               g_win32_stack_initialized = true;
+       }
+}
+
+/**
+ * Cleanup symbol table data.  This should be done in the
+ * primary thead at shutdown (under a lock if there are other
+ * threads active).
+ */
+void git_win32_leakcheck_stack_cleanup(void)
+{
+       if (g_win32_stack_initialized) {
+               SymCleanup(g_win32_stack_process);
+               g_win32_stack_process = INVALID_HANDLE_VALUE;
+               g_win32_stack_initialized = false;
+       }
+}
+
+int git_win32_leakcheck_stack_capture(git_win32_leakcheck_stack_raw_data *pdata, int skip)
+{
+       if (!g_win32_stack_initialized) {
+               git_error_set(GIT_ERROR_INVALID, "git_win32_stack not initialized.");
+               return GIT_ERROR;
+       }
+
+       memset(pdata, 0, sizeof(*pdata));
+       pdata->nr_frames = RtlCaptureStackBackTrace(
+               skip+1, GIT_WIN32_LEAKCHECK_STACK_MAX_FRAMES, pdata->frames, NULL);
+
+       /* If an "aux" data provider was registered, ask it to capture
+        * whatever data it needs and give us an "aux_id" to it so that
+        * we can refer to it later when reporting.
+        */
+       if (g_aux_cb_alloc)
+               (g_aux_cb_alloc)(&pdata->aux_id);
+
+       return 0;
+}
+
+int git_win32_leakcheck_stack_compare(
+       git_win32_leakcheck_stack_raw_data *d1,
+       git_win32_leakcheck_stack_raw_data *d2)
+{
+       return memcmp(d1, d2, sizeof(*d1));
+}
+
+int git_win32_leakcheck_stack_format(
+       char *pbuf, size_t buf_len,
+       const git_win32_leakcheck_stack_raw_data *pdata,
+       const char *prefix, const char *suffix)
+{
+#define MY_MAX_FILENAME 255
+
+       /* SYMBOL_INFO has char FileName[1] at the end.  The docs say to
+        * to malloc it with extra space for your desired max filename.
+        */
+       struct {
+               SYMBOL_INFO symbol;
+               char extra[MY_MAX_FILENAME + 1];
+       } s;
+
+       IMAGEHLP_LINE64 line;
+       size_t buf_used = 0;
+       unsigned int k;
+       char detail[MY_MAX_FILENAME * 2]; /* filename plus space for function name and formatting */
+       size_t detail_len;
+
+       if (!g_win32_stack_initialized) {
+               git_error_set(GIT_ERROR_INVALID, "git_win32_stack not initialized.");
+               return GIT_ERROR;
+       }
+
+       if (!prefix)
+               prefix = "\t";
+       if (!suffix)
+               suffix = "\n";
+
+       memset(pbuf, 0, buf_len);
+
+       memset(&s, 0, sizeof(s));
+       s.symbol.MaxNameLen = MY_MAX_FILENAME;
+       s.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
+
+       memset(&line, 0, sizeof(line));
+       line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+       for (k=0; k < pdata->nr_frames; k++) {
+               DWORD64 frame_k = (DWORD64)pdata->frames[k];
+               DWORD dwUnused;
+
+               if (SymFromAddr(g_win32_stack_process, frame_k, 0, &s.symbol) &&
+                       SymGetLineFromAddr64(g_win32_stack_process, frame_k, &dwUnused, &line)) {
+                       const char *pslash;
+                       const char *pfile;
+
+                       pslash = strrchr(line.FileName, '\\');
+                       pfile = ((pslash) ? (pslash+1) : line.FileName);
+                       p_snprintf(detail, sizeof(detail), "%s%s:%d> %s%s",
+                                          prefix, pfile, line.LineNumber, s.symbol.Name, suffix);
+               } else {
+                       /* This happens when we cross into another module.
+                        * For example, in CLAR tests, this is typically
+                        * the CRT startup code.  Just print an unknown
+                        * frame and continue.
+                        */
+                       p_snprintf(detail, sizeof(detail), "%s??%s", prefix, suffix);
+               }
+               detail_len = strlen(detail);
+
+               if (buf_len < (buf_used + detail_len + 1)) {
+                       /* we don't have room for this frame in the buffer, so just stop. */
+                       break;
+               }
+
+               memcpy(&pbuf[buf_used], detail, detail_len);
+               buf_used += detail_len;
+       }
+
+       /* "aux_id" 0 is reserved to mean no aux data. This is needed to handle
+        * allocs that occur before the aux callbacks were registered.
+        */
+       if (pdata->aux_id > 0) {
+               p_snprintf(detail, sizeof(detail), "%saux_id: %d%s",
+                                  prefix, pdata->aux_id, suffix);
+               detail_len = strlen(detail);
+               if ((buf_used + detail_len + 1) < buf_len) {
+                       memcpy(&pbuf[buf_used], detail, detail_len);
+                       buf_used += detail_len;
+               }
+
+               /* If an "aux" data provider is still registered, ask it to append its detailed
+                * data to the end of ours using the "aux_id" it gave us when this de-duped
+                * item was created.
+                */
+               if (g_aux_cb_lookup)
+                       (g_aux_cb_lookup)(pdata->aux_id, &pbuf[buf_used], (buf_len - buf_used - 1));
+       }
+
+       return GIT_OK;
+}
+
+int git_win32_leakcheck_stack(
+       char * pbuf, size_t buf_len,
+       int skip,
+       const char *prefix, const char *suffix)
+{
+       git_win32_leakcheck_stack_raw_data data;
+       int error;
+
+       if ((error = git_win32_leakcheck_stack_capture(&data, skip)) < 0)
+               return error;
+       if ((error = git_win32_leakcheck_stack_format(pbuf, buf_len, &data, prefix, suffix)) < 0)
+               return error;
+       return 0;
+}
+
+/* Strack tracing */
+
+#define STACKTRACE_UID_LEN (15)
+
+/**
+ * The stacktrace of an allocation can be distilled
+ * to a unique id based upon the stackframe pointers
+ * and ignoring any size arguments. We will use these
+ * UIDs as the (char const*) __FILE__ argument we
+ * give to the CRT malloc routines.
+ */
+typedef struct {
+       char uid[STACKTRACE_UID_LEN + 1];
+} git_win32_leakcheck_stacktrace_uid;
+
+/**
+ * All mallocs with the same stacktrace will be de-duped
+ * and aggregated into this row.
+ */
+typedef struct {
+       git_win32_leakcheck_stacktrace_uid uid; /* must be first */
+       git_win32_leakcheck_stack_raw_data raw_data;
+       unsigned int count_allocs; /* times this alloc signature seen since init */
+       unsigned int count_allocs_at_last_checkpoint; /* times since last mark */
+       unsigned int transient_count_leaks; /* sum of leaks */
+} git_win32_leakcheck_stacktrace_row;
+
+static CRITICAL_SECTION g_crtdbg_stacktrace_cs;
+
+/**
+ * CRTDBG memory leak tracking takes a "char const * const file_name"
+ * and stores the pointer in the heap data (instead of allocing a copy
+ * for itself).  Normally, this is not a problem, since we usually pass
+ * in __FILE__.  But I'm going to lie to it and pass in the address of
+ * the UID in place of the file_name.  Also, I do not want to alloc the
+ * stacktrace data (because we are called from inside our alloc routines).
+ * Therefore, I'm creating a very large static pool array to store row
+ * data. This also eliminates the temptation to realloc it (and move the
+ * UID pointers).
+ *
+ * And to efficiently look for duplicates we need an index on the rows
+ * so we can bsearch it.  Again, without mallocing.
+ *
+ * If we observe more than MY_ROW_LIMIT unique malloc signatures, we
+ * fall through and use the traditional __FILE__ processing and don't
+ * try to de-dup them.  If your testing hits this limit, just increase
+ * it and try again.
+ */
+
+#define MY_ROW_LIMIT (2 * 1024 * 1024)
+static git_win32_leakcheck_stacktrace_row  g_cs_rows[MY_ROW_LIMIT];
+static git_win32_leakcheck_stacktrace_row *g_cs_index[MY_ROW_LIMIT];
+
+static unsigned int g_cs_end = MY_ROW_LIMIT;
+static unsigned int g_cs_ins = 0; /* insertion point == unique allocs seen */
+static unsigned int g_count_total_allocs = 0; /* number of allocs seen */
+static unsigned int g_transient_count_total_leaks = 0; /* number of total leaks */
+static unsigned int g_transient_count_dedup_leaks = 0; /* number of unique leaks */
+static bool g_limit_reached = false; /* had allocs after we filled row table */
+
+static unsigned int g_checkpoint_id = 0; /* to better label leak checkpoints */
+static bool g_transient_leaks_since_mark = false; /* payload for hook */
+
+/**
+ * Compare function for bsearch on g_cs_index table.
+ */
+static int row_cmp(const void *v1, const void *v2)
+{
+       git_win32_leakcheck_stack_raw_data *d1 = (git_win32_leakcheck_stack_raw_data*)v1;
+       git_win32_leakcheck_stacktrace_row *r2 = (git_win32_leakcheck_stacktrace_row *)v2;
+
+       return (git_win32_leakcheck_stack_compare(d1, &r2->raw_data));
+}
+
+/**
+ * Unique insert the new data into the row and index tables.
+ * We have to sort by the stackframe data itself, not the uid.
+ */
+static git_win32_leakcheck_stacktrace_row * insert_unique(
+       const git_win32_leakcheck_stack_raw_data *pdata)
+{
+       size_t pos;
+       if (git__bsearch(g_cs_index, g_cs_ins, pdata, row_cmp, &pos) < 0) {
+               /* Append new unique item to row table. */
+               memcpy(&g_cs_rows[g_cs_ins].raw_data, pdata, sizeof(*pdata));
+               sprintf(g_cs_rows[g_cs_ins].uid.uid, "##%08lx", g_cs_ins);
+
+               /* Insert pointer to it into the proper place in the index table. */
+               if (pos < g_cs_ins)
+                       memmove(&g_cs_index[pos+1], &g_cs_index[pos], (g_cs_ins - pos)*sizeof(g_cs_index[0]));
+               g_cs_index[pos] = &g_cs_rows[g_cs_ins];
+
+               g_cs_ins++;
+       }
+
+       g_cs_index[pos]->count_allocs++;
+
+       return g_cs_index[pos];
+}
+
+/**
+ * Hook function to receive leak data from the CRT. (This includes
+ * both "<file_name>:(<line_number>)" data, but also each of the
+ * various headers and fields.
+ *
+ * Scan this for the special "##<pos>" UID forms that we substituted
+ * for the "<file_name>".  Map <pos> back to the row data and
+ * increment its leak count.
+ *
+ * See https://msdn.microsoft.com/en-us/library/74kabxyx.aspx
+ *
+ * We suppress the actual crtdbg output.
+ */
+static int __cdecl report_hook(int nRptType, char *szMsg, int *retVal)
+{
+       static int hook_result = TRUE; /* FALSE to get stock dump; TRUE to suppress. */
+       unsigned int pos;
+
+       *retVal = 0; /* do not invoke debugger */
+
+       if ((szMsg[0] != '#') || (szMsg[1] != '#'))
+               return hook_result;
+
+       if (sscanf(&szMsg[2], "%08lx", &pos) < 1)
+               return hook_result;
+       if (pos >= g_cs_ins)
+               return hook_result;
+
+       if (g_transient_leaks_since_mark) {
+               if (g_cs_rows[pos].count_allocs == g_cs_rows[pos].count_allocs_at_last_checkpoint)
+                       return hook_result;
+       }
+
+       g_cs_rows[pos].transient_count_leaks++;
+
+       if (g_cs_rows[pos].transient_count_leaks == 1)
+               g_transient_count_dedup_leaks++;
+
+       g_transient_count_total_leaks++;
+
+       return hook_result;
+}
+
+/**
+ * Write leak data to all of the various places we need.
+ * We force the caller to sprintf() the message first
+ * because we want to avoid fprintf() because it allocs.
+ */
+static void my_output(const char *buf)
+{
+       fwrite(buf, strlen(buf), 1, stderr);
+       OutputDebugString(buf);
+}
+
+/**
+ * For each row with leaks, dump a stacktrace for it.
+ */
+static void dump_summary(const char *label)
+{
+       unsigned int k;
+       char buf[10 * 1024];
+
+       if (g_transient_count_total_leaks == 0)
+               return;
+
+       fflush(stdout);
+       fflush(stderr);
+       my_output("\n");
+
+       if (g_limit_reached) {
+               sprintf(buf,
+                               "LEAK SUMMARY: de-dup row table[%d] filled. Increase MY_ROW_LIMIT.\n",
+                               MY_ROW_LIMIT);
+               my_output(buf);
+       }
+
+       if (!label)
+               label = "";
+
+       if (g_transient_leaks_since_mark) {
+               sprintf(buf, "LEAK CHECKPOINT %d: leaks %d unique %d: %s\n",
+                               g_checkpoint_id, g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
+               my_output(buf);
+       } else {
+               sprintf(buf, "LEAK SUMMARY: TOTAL leaks %d de-duped %d: %s\n",
+                               g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
+               my_output(buf);
+       }
+       my_output("\n");
+
+       for (k = 0; k < g_cs_ins; k++) {
+               if (g_cs_rows[k].transient_count_leaks > 0) {
+                       sprintf(buf, "LEAK: %s leaked %d of %d times:\n",
+                                       g_cs_rows[k].uid.uid,
+                                       g_cs_rows[k].transient_count_leaks,
+                                       g_cs_rows[k].count_allocs);
+                       my_output(buf);
+
+                       if (git_win32_leakcheck_stack_format(
+                                       buf, sizeof(buf), &g_cs_rows[k].raw_data,
+                                       NULL, NULL) >= 0) {
+                               my_output(buf);
+                       }
+
+                       my_output("\n");
+               }
+       }
+
+       fflush(stderr);
+}
+
+/**
+ * Initialize our memory leak tracking and de-dup data structures.
+ * This should ONLY be called by git_libgit2_init().
+ */
+void git_win32_leakcheck_stacktrace_init(void)
+{
+       InitializeCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+
+       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
+       _CrtSetReportMode(_CRT_ERROR,  _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
+       _CrtSetReportMode(_CRT_WARN,   _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
+
+       _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+       _CrtSetReportFile(_CRT_ERROR,  _CRTDBG_FILE_STDERR);
+       _CrtSetReportFile(_CRT_WARN,   _CRTDBG_FILE_STDERR);
+
+       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
+}
+
+int git_win32_leakcheck_stacktrace_dump(
+       git_win32_leakcheck_stacktrace_options opt,
+       const char *label)
+{
+       _CRT_REPORT_HOOK old;
+       unsigned int k;
+       int r = 0;
+
+#define IS_BIT_SET(o,b) (((o) & (b)) != 0)
+
+       bool b_set_mark         = IS_BIT_SET(opt, GIT_WIN32_LEAKCHECK_STACKTRACE_SET_MARK);
+       bool b_leaks_since_mark = IS_BIT_SET(opt, GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK);
+       bool b_leaks_total      = IS_BIT_SET(opt, GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_TOTAL);
+       bool b_quiet            = IS_BIT_SET(opt, GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET);
+
+       if (b_leaks_since_mark && b_leaks_total) {
+               git_error_set(GIT_ERROR_INVALID, "cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL.");
+               return GIT_ERROR;
+       }
+       if (!b_set_mark && !b_leaks_since_mark && !b_leaks_total) {
+               git_error_set(GIT_ERROR_INVALID, "nothing to do.");
+               return GIT_ERROR;
+       }
+
+       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       if (b_leaks_since_mark || b_leaks_total) {
+               /* All variables with "transient" in the name are per-dump counters
+                * and reset before each dump.  This lets us handle checkpoints.
+                */
+               g_transient_count_total_leaks = 0;
+               g_transient_count_dedup_leaks = 0;
+               for (k = 0; k < g_cs_ins; k++) {
+                       g_cs_rows[k].transient_count_leaks = 0;
+               }
+       }
+
+       g_transient_leaks_since_mark = b_leaks_since_mark;
+
+       old = _CrtSetReportHook(report_hook);
+       _CrtDumpMemoryLeaks();
+       _CrtSetReportHook(old);
+
+       if (b_leaks_since_mark || b_leaks_total) {
+               r = g_transient_count_dedup_leaks;
+
+               if (!b_quiet)
+                       dump_summary(label);
+       }
+
+       if (b_set_mark) {
+               for (k = 0; k < g_cs_ins; k++) {
+                       g_cs_rows[k].count_allocs_at_last_checkpoint = g_cs_rows[k].count_allocs;
+               }
+
+               g_checkpoint_id++;
+       }
+
+       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       return r;
+}
+
+/**
+ * Shutdown our memory leak tracking and dump summary data.
+ * This should ONLY be called by git_libgit2_shutdown().
+ *
+ * We explicitly call _CrtDumpMemoryLeaks() during here so
+ * that we can compute summary data for the leaks. We print
+ * the stacktrace of each unique leak.
+ *
+ * This cleanup does not happen if the app calls exit()
+ * without calling the libgit2 shutdown code.
+ *
+ * This info we print here is independent of any automatic
+ * reporting during exit() caused by _CRTDBG_LEAK_CHECK_DF.
+ * Set it in your app if you also want traditional reporting.
+ */
+void git_win32_leakcheck_stacktrace_cleanup(void)
+{
+       /* At shutdown/cleanup, dump cumulative leak info
+        * with everything since startup.  This might generate
+        * extra noise if the caller has been doing checkpoint
+        * dumps, but it might also eliminate some false
+        * positives for resources previously reported during
+        * checkpoints.
+        */
+       git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_TOTAL,
+               "CLEANUP");
+
+       DeleteCriticalSection(&g_crtdbg_stacktrace_cs);
+}
+
+const char *git_win32_leakcheck_stacktrace(int skip, const char *file)
+{
+       git_win32_leakcheck_stack_raw_data new_data;
+       git_win32_leakcheck_stacktrace_row *row;
+       const char * result = file;
+
+       if (git_win32_leakcheck_stack_capture(&new_data, skip+1) < 0)
+               return result;
+
+       EnterCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       if (g_cs_ins < g_cs_end) {
+               row = insert_unique(&new_data);
+               result = row->uid.uid;
+       } else {
+               g_limit_reached = true;
+       }
+
+       g_count_total_allocs++;
+
+       LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
+
+       return result;
+}
+
+static void git_win32_leakcheck_global_shutdown(void)
+{
+       git_win32_leakcheck_stacktrace_cleanup();
+       git_win32_leakcheck_stack_cleanup();
+}
+
+bool git_win32_leakcheck_has_leaks(void)
+{
+       return (g_transient_count_total_leaks > 0);
+}
+
+int git_win32_leakcheck_global_init(void)
+{
+       git_win32_leakcheck_stacktrace_init();
+       git_win32_leakcheck_stack_init();
+
+       return git_runtime_shutdown_register(git_win32_leakcheck_global_shutdown);
+}
+
+#else
+
+int git_win32_leakcheck_global_init(void)
+{
+       return 0;
+}
+
+#endif
diff --git a/src/win32/w32_leakcheck.h b/src/win32/w32_leakcheck.h
new file mode 100644 (file)
index 0000000..cb45e36
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_win32_leakcheck_h__
+#define INCLUDE_win32_leakcheck_h__
+
+#include "common.h"
+
+/* Initialize the win32 leak checking system. */
+int git_win32_leakcheck_global_init(void);
+
+#if defined(GIT_WIN32_LEAKCHECK)
+
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#include "git2/errors.h"
+#include "strnlen.h"
+
+bool git_win32_leakcheck_has_leaks(void);
+
+/* Stack frames (for stack tracing, below) */
+
+/**
+ * This type defines a callback to be used to augment a C stacktrace
+ * with "aux" data. This can be used, for example, to allow LibGit2Sharp
+ * (or other interpreted consumer libraries) to give us C# stacktrace
+ * data for the PInvoke.
+ *
+ * This callback will be called during crtdbg-instrumented allocs.
+ *
+ * @param aux_id [out] A returned "aux_id" representing a unique
+ * (de-duped at the C# layer) stacktrace.  "aux_id" 0 is reserved
+ * to mean no aux stacktrace data.
+ */
+typedef void (*git_win32_leakcheck_stack_aux_cb_alloc)(unsigned int *aux_id);
+
+/**
+ * This type defines a callback to be used to augment the output of
+ * a stacktrace.  This will be used to request the C# layer format
+ * the C# stacktrace associated with "aux_id" into the provided
+ * buffer.
+ *
+ * This callback will be called during leak reporting.
+ *
+ * @param aux_id The "aux_id" key associated with a stacktrace.
+ * @param aux_msg A buffer where a formatted message should be written.
+ * @param aux_msg_len The size of the buffer.
+ */
+typedef void (*git_win32_leakcheck_stack_aux_cb_lookup)(unsigned int aux_id, char *aux_msg, size_t aux_msg_len);
+
+/**
+ * Register an "aux" data provider to augment our C stacktrace data.
+ *
+ * This can be used, for example, to allow LibGit2Sharp (or other
+ * interpreted consumer libraries) to give us the C# stacktrace of
+ * the PInvoke.
+ *
+ * If you choose to use this feature, it should be registered during
+ * initialization and not changed for the duration of the process.
+ */
+int git_win32_leakcheck_stack_set_aux_cb(
+       git_win32_leakcheck_stack_aux_cb_alloc cb_alloc,
+       git_win32_leakcheck_stack_aux_cb_lookup cb_lookup);
+
+/**
+ * Maximum number of stackframes to record for a
+ * single stacktrace.
+ */
+#define GIT_WIN32_LEAKCHECK_STACK_MAX_FRAMES 30
+
+/**
+ * Wrapper containing the raw unprocessed stackframe
+ * data for a single stacktrace and any "aux_id".
+ *
+ * I put the aux_id first so leaks will be sorted by it.
+ * So, for example, if a specific callstack in C# leaks
+ * a repo handle, all of the pointers within the associated
+ * repo pointer will be grouped together.
+ */
+typedef struct {
+       unsigned int aux_id;
+       unsigned int nr_frames;
+       void *frames[GIT_WIN32_LEAKCHECK_STACK_MAX_FRAMES];
+} git_win32_leakcheck_stack_raw_data;
+
+/**
+ * Capture raw stack trace data for the current process/thread.
+ *
+ * @param skip Number of initial frames to skip.  Pass 0 to
+ * begin with the caller of this routine. Pass 1 to begin
+ * with its caller.  And so on.
+ */
+int git_win32_leakcheck_stack_capture(git_win32_leakcheck_stack_raw_data *pdata, int skip);
+
+/**
+ * Compare 2 raw stacktraces with the usual -1,0,+1 result.
+ * This includes any "aux_id" values in the comparison, so that
+ * our de-dup is also "aux" context relative.
+ */
+int git_win32_leakcheck_stack_compare(
+       git_win32_leakcheck_stack_raw_data *d1,
+       git_win32_leakcheck_stack_raw_data *d2);
+
+/**
+ * Format raw stacktrace data into buffer WITHOUT using any mallocs.
+ *
+ * @param prefix String written before each frame; defaults to "\t".
+ * @param suffix String written after each frame; defaults to "\n".
+ */
+int git_win32_leakcheck_stack_format(
+       char *pbuf, size_t buf_len,
+       const git_win32_leakcheck_stack_raw_data *pdata,
+       const char *prefix, const char *suffix);
+
+/**
+ * Convenience routine to capture and format stacktrace into
+ * a buffer WITHOUT using any mallocs.  This is primarily a
+ * wrapper for testing.
+ *
+ * @param skip Number of initial frames to skip. Pass 0 to
+ * begin with the caller of this routine.  Pass 1 to begin
+ * with its caller.  And so on.
+ * @param prefix String written before each frame; defaults to "\t".
+ * @param suffix String written after each frame; defaults to "\n".
+ */
+int git_win32_leakcheck_stack(
+       char * pbuf, size_t buf_len,
+       int skip,
+       const char *prefix, const char *suffix);
+
+/* Stack tracing */
+
+/* MSVC CRTDBG memory leak reporting.
+ *
+ * We DO NOT use the "_CRTDBG_MAP_ALLOC" macro described in the MSVC
+ * documentation because all allocs/frees in libgit2 already go through
+ * the "git__" routines defined in this file.  Simply using the normal
+ * reporting mechanism causes all leaks to be attributed to a routine
+ * here in util.h (ie, the actual call to calloc()) rather than the
+ * caller of git__calloc().
+ *
+ * Therefore, we declare a set of "git__crtdbg__" routines to replace
+ * the corresponding "git__" routines and re-define the "git__" symbols
+ * as macros.  This allows us to get and report the file:line info of
+ * the real caller.
+ *
+ * We DO NOT replace the "git__free" routine because it needs to remain
+ * a function pointer because it is used as a function argument when
+ * setting up various structure "destructors".
+ *
+ * We also DO NOT use the "_CRTDBG_MAP_ALLOC" macro because it causes
+ * "free" to be remapped to "_free_dbg" and this causes problems for
+ * structures which define a field named "free".
+ *
+ * Finally, CRTDBG must be explicitly enabled and configured at program
+ * startup.  See tests/main.c for an example.
+ */
+
+/**
+ * Checkpoint options.
+ */
+typedef enum git_win32_leakcheck_stacktrace_options {
+       /**
+        * Set checkpoint marker.
+        */
+       GIT_WIN32_LEAKCHECK_STACKTRACE_SET_MARK         = (1 << 0),
+
+       /**
+        * Dump leaks since last checkpoint marker.
+        * May not be combined with _LEAKS_TOTAL.
+        *
+        * Note that this may generate false positives for global TLS
+        * error state and other global caches that aren't cleaned up
+        * until the thread/process terminates.  So when using this
+        * around a region of interest, also check the final (at exit)
+        * dump before digging into leaks reported here.
+        */
+       GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK = (1 << 1),
+
+       /**
+        * Dump leaks since init.  May not be combined
+        * with _LEAKS_SINCE_MARK.
+        */
+       GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_TOTAL      = (1 << 2),
+
+       /**
+        * Suppress printing during dumps.
+        * Just return leak count.
+        */
+       GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET            = (1 << 3),
+
+} git_win32_leakcheck_stacktrace_options;
+
+/**
+ * Checkpoint memory state and/or dump unique stack traces of
+ * current memory leaks.
+ *
+ * @return number of unique leaks (relative to requested starting
+ * point) or error.
+ */
+int git_win32_leakcheck_stacktrace_dump(
+       git_win32_leakcheck_stacktrace_options opt,
+       const char *label);
+
+/**
+ * Construct stacktrace and append it to the global buffer.
+ * Return pointer to start of this string.  On any error or
+ * lack of buffer space, just return the given file buffer
+ * so it will behave as usual.
+ *
+ * This should ONLY be called by our internal memory allocations
+ * routines.
+ */
+const char *git_win32_leakcheck_stacktrace(int skip, const char *file);
+
+#endif
+#endif
diff --git a/src/win32/w32_stack.c b/src/win32/w32_stack.c
deleted file mode 100644 (file)
index 78c78db..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "w32_stack.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-#include "Windows.h"
-#include "Dbghelp.h"
-#include "win32/posix.h"
-#include "hash.h"
-
-static bool   g_win32_stack_initialized = false;
-static HANDLE g_win32_stack_process = INVALID_HANDLE_VALUE;
-static git_win32__stack__aux_cb_alloc  g_aux_cb_alloc  = NULL;
-static git_win32__stack__aux_cb_lookup g_aux_cb_lookup = NULL;
-
-int git_win32__stack__set_aux_cb(
-       git_win32__stack__aux_cb_alloc cb_alloc,
-       git_win32__stack__aux_cb_lookup cb_lookup)
-{
-       g_aux_cb_alloc = cb_alloc;
-       g_aux_cb_lookup = cb_lookup;
-
-       return 0;
-}
-
-void git_win32__stack_init(void)
-{
-       if (!g_win32_stack_initialized) {
-               g_win32_stack_process = GetCurrentProcess();
-               SymSetOptions(SYMOPT_LOAD_LINES);
-               SymInitialize(g_win32_stack_process, NULL, TRUE);
-               g_win32_stack_initialized = true;
-       }
-}
-
-void git_win32__stack_cleanup(void)
-{
-       if (g_win32_stack_initialized) {
-               SymCleanup(g_win32_stack_process);
-               g_win32_stack_process = INVALID_HANDLE_VALUE;
-               g_win32_stack_initialized = false;
-       }
-}
-
-int git_win32__stack_capture(git_win32__stack__raw_data *pdata, int skip)
-{
-       if (!g_win32_stack_initialized) {
-               git_error_set(GIT_ERROR_INVALID, "git_win32_stack not initialized.");
-               return GIT_ERROR;
-       }
-
-       memset(pdata, 0, sizeof(*pdata));
-       pdata->nr_frames = RtlCaptureStackBackTrace(
-               skip+1, GIT_WIN32__STACK__MAX_FRAMES, pdata->frames, NULL);
-
-       /* If an "aux" data provider was registered, ask it to capture
-        * whatever data it needs and give us an "aux_id" to it so that
-        * we can refer to it later when reporting.
-        */
-       if (g_aux_cb_alloc)
-               (g_aux_cb_alloc)(&pdata->aux_id);
-
-       return 0;
-}
-
-int git_win32__stack_compare(
-       git_win32__stack__raw_data *d1,
-       git_win32__stack__raw_data *d2)
-{
-       return memcmp(d1, d2, sizeof(*d1));
-}
-
-int git_win32__stack_format(
-       char *pbuf, size_t buf_len,
-       const git_win32__stack__raw_data *pdata,
-       const char *prefix, const char *suffix)
-{
-#define MY_MAX_FILENAME 255
-
-       /* SYMBOL_INFO has char FileName[1] at the end.  The docs say to
-        * to malloc it with extra space for your desired max filename.
-        */
-       struct {
-               SYMBOL_INFO symbol;
-               char extra[MY_MAX_FILENAME + 1];
-       } s;
-
-       IMAGEHLP_LINE64 line;
-       size_t buf_used = 0;
-       unsigned int k;
-       char detail[MY_MAX_FILENAME * 2]; /* filename plus space for function name and formatting */
-       size_t detail_len;
-
-       if (!g_win32_stack_initialized) {
-               git_error_set(GIT_ERROR_INVALID, "git_win32_stack not initialized.");
-               return GIT_ERROR;
-       }
-
-       if (!prefix)
-               prefix = "\t";
-       if (!suffix)
-               suffix = "\n";
-
-       memset(pbuf, 0, buf_len);
-
-       memset(&s, 0, sizeof(s));
-       s.symbol.MaxNameLen = MY_MAX_FILENAME;
-       s.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
-
-       memset(&line, 0, sizeof(line));
-       line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
-
-       for (k=0; k < pdata->nr_frames; k++) {
-               DWORD64 frame_k = (DWORD64)pdata->frames[k];
-               DWORD dwUnused;
-
-               if (SymFromAddr(g_win32_stack_process, frame_k, 0, &s.symbol) &&
-                       SymGetLineFromAddr64(g_win32_stack_process, frame_k, &dwUnused, &line)) {
-                       const char *pslash;
-                       const char *pfile;
-
-                       pslash = strrchr(line.FileName, '\\');
-                       pfile = ((pslash) ? (pslash+1) : line.FileName);
-                       p_snprintf(detail, sizeof(detail), "%s%s:%d> %s%s",
-                                          prefix, pfile, line.LineNumber, s.symbol.Name, suffix);
-               } else {
-                       /* This happens when we cross into another module.
-                        * For example, in CLAR tests, this is typically
-                        * the CRT startup code.  Just print an unknown
-                        * frame and continue.
-                        */
-                       p_snprintf(detail, sizeof(detail), "%s??%s", prefix, suffix);
-               }
-               detail_len = strlen(detail);
-
-               if (buf_len < (buf_used + detail_len + 1)) {
-                       /* we don't have room for this frame in the buffer, so just stop. */
-                       break;
-               }
-
-               memcpy(&pbuf[buf_used], detail, detail_len);
-               buf_used += detail_len;
-       }
-
-       /* "aux_id" 0 is reserved to mean no aux data. This is needed to handle
-        * allocs that occur before the aux callbacks were registered.
-        */
-       if (pdata->aux_id > 0) {
-               p_snprintf(detail, sizeof(detail), "%saux_id: %d%s",
-                                  prefix, pdata->aux_id, suffix);
-               detail_len = strlen(detail);
-               if ((buf_used + detail_len + 1) < buf_len) {
-                       memcpy(&pbuf[buf_used], detail, detail_len);
-                       buf_used += detail_len;
-               }
-
-               /* If an "aux" data provider is still registered, ask it to append its detailed
-                * data to the end of ours using the "aux_id" it gave us when this de-duped
-                * item was created.
-                */
-               if (g_aux_cb_lookup)
-                       (g_aux_cb_lookup)(pdata->aux_id, &pbuf[buf_used], (buf_len - buf_used - 1));
-       }
-
-       return GIT_OK;
-}
-
-int git_win32__stack(
-       char * pbuf, size_t buf_len,
-       int skip,
-       const char *prefix, const char *suffix)
-{
-       git_win32__stack__raw_data data;
-       int error;
-
-       if ((error = git_win32__stack_capture(&data, skip)) < 0)
-               return error;
-       if ((error = git_win32__stack_format(pbuf, buf_len, &data, prefix, suffix)) < 0)
-               return error;
-       return 0;
-}
-
-#endif
diff --git a/src/win32/w32_stack.h b/src/win32/w32_stack.h
deleted file mode 100644 (file)
index c2565c2..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_win32_w32_stack_h__
-#define INCLUDE_win32_w32_stack_h__
-
-#include "common.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-
-/**
- * This type defines a callback to be used to augment a C stacktrace
- * with "aux" data. This can be used, for example, to allow LibGit2Sharp
- * (or other interpreted consumer libraries) to give us C# stacktrace
- * data for the PInvoke.
- *
- * This callback will be called during crtdbg-instrumented allocs.
- *
- * @param aux_id [out] A returned "aux_id" representing a unique
- * (de-duped at the C# layer) stacktrace.  "aux_id" 0 is reserved
- * to mean no aux stacktrace data.
- */
-typedef void (*git_win32__stack__aux_cb_alloc)(unsigned int *aux_id);
-
-/**
- * This type defines a callback to be used to augment the output of
- * a stacktrace.  This will be used to request the C# layer format
- * the C# stacktrace associated with "aux_id" into the provided
- * buffer.
- *
- * This callback will be called during leak reporting.
- *
- * @param aux_id The "aux_id" key associated with a stacktrace.
- * @param aux_msg A buffer where a formatted message should be written.
- * @param aux_msg_len The size of the buffer.
- */
-typedef void (*git_win32__stack__aux_cb_lookup)(unsigned int aux_id, char *aux_msg, size_t aux_msg_len);
-
-/**
- * Register an "aux" data provider to augment our C stacktrace data.
- *
- * This can be used, for example, to allow LibGit2Sharp (or other
- * interpreted consumer libraries) to give us the C# stacktrace of
- * the PInvoke.
- *
- * If you choose to use this feature, it should be registered during
- * initialization and not changed for the duration of the process.
- */
-GIT_EXTERN(int) git_win32__stack__set_aux_cb(
-       git_win32__stack__aux_cb_alloc cb_alloc,
-       git_win32__stack__aux_cb_lookup cb_lookup);
-
-/**
- * Maximum number of stackframes to record for a
- * single stacktrace.
- */
-#define GIT_WIN32__STACK__MAX_FRAMES 30
-
-/**
- * Wrapper containing the raw unprocessed stackframe
- * data for a single stacktrace and any "aux_id".
- *
- * I put the aux_id first so leaks will be sorted by it.
- * So, for example, if a specific callstack in C# leaks
- * a repo handle, all of the pointers within the associated
- * repo pointer will be grouped together.
- */
-typedef struct {
-       unsigned int aux_id;
-       unsigned int nr_frames;
-       void *frames[GIT_WIN32__STACK__MAX_FRAMES];
-} git_win32__stack__raw_data;
-
-
-/**
- * Load symbol table data.  This should be done in the primary
- * thread at startup (under a lock if there are other threads
- * active).
- */
-void git_win32__stack_init(void);
-
-/**
- * Cleanup symbol table data.  This should be done in the
- * primary thead at shutdown (under a lock if there are other
- * threads active).
- */
-void git_win32__stack_cleanup(void);
-
-
-/**
- * Capture raw stack trace data for the current process/thread.
- *
- * @param skip Number of initial frames to skip.  Pass 0 to
- * begin with the caller of this routine. Pass 1 to begin
- * with its caller.  And so on.
- */
-int git_win32__stack_capture(git_win32__stack__raw_data *pdata, int skip);
-
-/**
- * Compare 2 raw stacktraces with the usual -1,0,+1 result.
- * This includes any "aux_id" values in the comparison, so that
- * our de-dup is also "aux" context relative.
- */
-int git_win32__stack_compare(
-       git_win32__stack__raw_data *d1,
-       git_win32__stack__raw_data *d2);
-
-/**
- * Format raw stacktrace data into buffer WITHOUT using any mallocs.
- *
- * @param prefix String written before each frame; defaults to "\t".
- * @param suffix String written after each frame; defaults to "\n".
- */
-int git_win32__stack_format(
-       char *pbuf, size_t buf_len,
-       const git_win32__stack__raw_data *pdata,
-       const char *prefix, const char *suffix);
-
-/**
- * Convenience routine to capture and format stacktrace into
- * a buffer WITHOUT using any mallocs.  This is primarily a
- * wrapper for testing.
- *
- * @param skip Number of initial frames to skip. Pass 0 to
- * begin with the caller of this routine.  Pass 1 to begin
- * with its caller.  And so on.
- * @param prefix String written before each frame; defaults to "\t".
- * @param suffix String written after each frame; defaults to "\n".
- */
-int git_win32__stack(
-       char * pbuf, size_t buf_len,
-       int skip,
-       const char *prefix, const char *suffix);
-
-#endif /* GIT_MSVC_CRTDBG */
-#endif
index d7f9d3da6d8240ff238ea837381097b33969b52d..1321d30e66b4493f5ca4da5e856267eed77cb3b7 100644 (file)
@@ -74,8 +74,8 @@ GIT_INLINE(void) git_win32__filetime_to_timespec(
        const FILETIME *ft,
        struct timespec *ts)
 {
-       long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
-       winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
+       int64_t winTime = ((int64_t)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
+       winTime -= INT64_C(116444736000000000); /* Windows to Unix Epoch conversion */
        ts->tv_sec = (time_t)(winTime / 10000000);
 #ifdef GIT_USE_NSEC
        ts->tv_nsec = (winTime % 10000000) * 100;
@@ -87,11 +87,11 @@ GIT_INLINE(void) git_win32__filetime_to_timespec(
 GIT_INLINE(void) git_win32__timeval_to_filetime(
        FILETIME *ft, const struct p_timeval tv)
 {
-       long long ticks = (tv.tv_sec * 10000000LL) +
-               (tv.tv_usec * 10LL) + 116444736000000000LL;
+       int64_t ticks = (tv.tv_sec * INT64_C(10000000)) +
+               (tv.tv_usec * INT64_C(10)) + INT64_C(116444736000000000);
 
-       ft->dwHighDateTime = ((ticks >> 32) & 0xffffffffLL);
-       ft->dwLowDateTime = (ticks & 0xffffffffLL);
+       ft->dwHighDateTime = ((ticks >> 32) & INT64_C(0xffffffff));
+       ft->dwLowDateTime = (ticks & INT64_C(0xffffffff));
 }
 
 GIT_INLINE(void) git_win32__stat_init(
index fda9b0b71ab99d4e147e01c054e42a7d3b272ae1..fe8db774305ba58c440574e349f768c78582ac1e 100644 (file)
@@ -37,12 +37,13 @@ int git_worktree_list(git_strarray *wts, git_repository *repo)
        size_t i, len;
        int error;
 
-       assert(wts && repo);
+       GIT_ASSERT_ARG(wts);
+       GIT_ASSERT_ARG(repo);
 
        wts->count = 0;
        wts->strings = NULL;
 
-       if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0)
+       if ((error = git_buf_joinpath(&path, repo->commondir, "worktrees/")) < 0)
                goto exit;
        if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
                goto exit;
@@ -73,7 +74,8 @@ char *git_worktree__read_link(const char *base, const char *file)
 {
        git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
 
-       assert(base && file);
+       GIT_ASSERT_ARG_WITH_RETVAL(base, NULL);
+       GIT_ASSERT_ARG_WITH_RETVAL(file, NULL);
 
        if (git_buf_joinpath(&path, base, file) < 0)
                goto err;
@@ -106,7 +108,9 @@ static int write_wtfile(const char *base, const char *file, const git_buf *buf)
        git_buf path = GIT_BUF_INIT;
        int err;
 
-       assert(base && file && buf);
+       GIT_ASSERT_ARG(base);
+       GIT_ASSERT_ARG(file);
+       GIT_ASSERT_ARG(buf);
 
        if ((err = git_buf_joinpath(&path, base, file)) < 0)
                goto out;
@@ -131,6 +135,9 @@ static int open_worktree_dir(git_worktree **out, const char *parent, const char
                goto out;
        }
 
+       if ((error = git_path_validate_workdir(NULL, dir)) < 0)
+               goto out;
+
        if ((wt = git__calloc(1, sizeof(*wt))) == NULL) {
                error = -1;
                goto out;
@@ -170,11 +177,12 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na
        git_worktree *wt = NULL;
        int error;
 
-       assert(repo && name);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
 
        *out = NULL;
 
-       if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
+       if ((error = git_buf_join3(&path, '/', repo->commondir, "worktrees", name)) < 0)
                goto out;
 
        if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0)
@@ -237,7 +245,7 @@ void git_worktree_free(git_worktree *wt)
 
 int git_worktree_validate(const git_worktree *wt)
 {
-       assert(wt);
+       GIT_ASSERT_ARG(wt);
 
        if (!is_worktree_dir(wt->gitdir_path)) {
                git_error_set(GIT_ERROR_WORKTREE,
@@ -260,6 +268,13 @@ int git_worktree_validate(const git_worktree *wt)
                return GIT_ERROR;
        }
 
+       if (!git_path_exists(wt->worktree_path)) {
+               git_error_set(GIT_ERROR_WORKTREE,
+                       "worktree directory '%s' does not exist",
+                       wt->worktree_path);
+               return GIT_ERROR;
+       }
+
        return 0;
 }
 
@@ -297,7 +312,10 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
        if (opts)
                memcpy(&wtopts, opts, sizeof(wtopts));
 
-       assert(out && repo && name && worktree);
+       GIT_ASSERT_ARG(out);
+       GIT_ASSERT_ARG(repo);
+       GIT_ASSERT_ARG(name);
+       GIT_ASSERT_ARG(worktree);
 
        *out = NULL;
 
@@ -410,7 +428,7 @@ int git_worktree_lock(git_worktree *wt, const char *reason)
        git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
        int error;
 
-       assert(wt);
+       GIT_ASSERT_ARG(wt);
 
        if ((error = git_worktree_is_locked(NULL, wt)) < 0)
                goto out;
@@ -441,7 +459,7 @@ int git_worktree_unlock(git_worktree *wt)
        git_buf path = GIT_BUF_INIT;
        int error;
 
-       assert(wt);
+       GIT_ASSERT_ARG(wt);
 
        if ((error = git_worktree_is_locked(NULL, wt)) < 0)
                return error;
@@ -468,7 +486,7 @@ int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
        git_buf path = GIT_BUF_INIT;
        int error, locked;
 
-       assert(wt);
+       GIT_ASSERT_ARG(wt);
 
        if (reason)
                git_buf_clear(reason);
@@ -489,13 +507,13 @@ out:
 
 const char *git_worktree_name(const git_worktree *wt)
 {
-       assert(wt);
+       GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL);
        return wt->name;
 }
 
 const char *git_worktree_path(const git_worktree *wt)
 {
-       assert(wt);
+       GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL);
        return wt->worktree_path;
 }
 
@@ -574,7 +592,7 @@ int git_worktree_prune(git_worktree *wt,
        }
 
        /* Delete gitdir in parent repository */
-       if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name)) < 0)
+       if ((err = git_buf_join3(&path, '/', wt->commondir_path, "worktrees", wt->name)) < 0)
                goto out;
        if (!git_path_exists(path.ptr))
        {
index 975ead2f6fbccbfa63d76a7bbb6348e11ee727d4..a5675676e903973a412f7aaa0a07ad45f586c02b 100644 (file)
@@ -156,7 +156,7 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
        }
 
        /* either we finished the input or we did not flush the data */
-       assert(zstream->in_len > 0 || zstream->flush == Z_FINISH);
+       GIT_ASSERT(zstream->in_len > 0 || zstream->flush == Z_FINISH);
 
        /* set out_size to number of bytes actually written to output */
        *out_len = *out_len - out_remain;
index 6f8a18ec048d861941540ad152a91bf6282f5c0e..49999f4815e4a8ae40638fb68f1c2f890dd8ed93 100644 (file)
@@ -1,3 +1,4 @@
+SET(Python_ADDITIONAL_VERSIONS 3 2.7)
 FIND_PACKAGE(PythonInterp)
 
 IF(NOT PYTHONINTERP_FOUND)
@@ -9,6 +10,7 @@ SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/resources/")
 SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
 ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\")
 ADD_DEFINITIONS(-DCLAR_TMPDIR=\"libgit2_tests\")
+ADD_DEFINITIONS(-DCLAR_WIN32_LONGPATHS)
 ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
 
 # Ensure that we do not use deprecated functions internally
@@ -62,7 +64,8 @@ ENDFUNCTION(ADD_CLAR_TEST)
 
 ADD_CLAR_TEST(offline             -v -xonline)
 ADD_CLAR_TEST(invasive            -v -score::ftruncate -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root)
-ADD_CLAR_TEST(online              -v -sonline)
+ADD_CLAR_TEST(online              -v -sonline -xonline::customcert)
+ADD_CLAR_TEST(online_customcert   -v -sonline::customcert)
 ADD_CLAR_TEST(gitdaemon           -v -sonline::push)
 ADD_CLAR_TEST(ssh                 -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh)
 ADD_CLAR_TEST(proxy               -v -sonline::clone::proxy)
index 2d0019abf246f09947b6ee9caf9bfdc854d9e247..82094773e151c1471dddd28886daf9089507ac5d 100644 (file)
        "-asparagus which had been laid by, boil it until these last articles are\n" \
        "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n"
 
+#define DIFF_ADD_INVALID_FILENAME \
+       "diff --git a/.git/hello_world.txt b/.git/hello_world.txt\n" \
+       "new file mode 100644\n" \
+       "index 0000000..f75ba05\n" \
+       "--- /dev/null\n" \
+       "+++ b/.git/hello_world.txt\n" \
+       "@@ -0,0 +1 @@\n" \
+       "+Hello, world.\n"
+
 void validate_apply_workdir(
        git_repository *repo,
        struct merge_index_entry *workdir_entries,
index 400df5e3861170c7035042486a135436c44a517d..1089632702560bb313e30b2eb9b44138ef545d64 100644 (file)
@@ -734,3 +734,14 @@ void test_apply_both__cant_remove_file_twice(void)
 
        git_diff_free(diff);
 }
+
+void test_apply_both__cant_add_invalid_filename(void)
+{
+       git_diff *diff;
+
+       cl_git_pass(git_diff_from_buffer(&diff, DIFF_ADD_INVALID_FILENAME,
+               strlen(DIFF_ADD_INVALID_FILENAME)));
+       cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
+
+       git_diff_free(diff);
+}
index e9329f6d3fbd46a38a4649458978995f16d4c3aa..69dfe0987a8989deb4579749f85a31fb9262ca7e 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "apply.h"
 #include "repository.h"
-#include "buf_text.h"
 
 #include "../patch/patch_common.h"
 
index 477e283adcb008c8155513f4b1d019eccfb4cfd3..ae519eab051098a9b759727bffa8f9290c10991a 100644 (file)
@@ -5,7 +5,6 @@
 #include "patch.h"
 #include "patch_parse.h"
 #include "repository.h"
-#include "buf_text.h"
 
 #include "../patch/patch_common.h"
 
index 466a92717746205fe51e6d7e98ab02d7810a3c57..548faaadb14741205d10539d710080999383fc46 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "apply.h"
 #include "repository.h"
-#include "buf_text.h"
 
 #include "../patch/patch_common.h"
 
index 6063468cb46502144a188c6a752fb5489b43ca6e..f19f38fbb3ae632d79bf542c579f07dcfd3a3d0b 100644 (file)
@@ -236,6 +236,7 @@ void test_attr_lookup__check_attr_examples(void)
 void test_attr_lookup__from_buffer(void)
 {
        git_attr_file *file;
+       git_attr_file_source source = {0};
 
        struct attr_expected cases[] = {
                { "abc", "foo", EXPECT_TRUE, NULL },
@@ -250,7 +251,7 @@ void test_attr_lookup__from_buffer(void)
                { NULL, NULL, 0, NULL }
        };
 
-       cl_git_pass(git_attr_file__new(&file, NULL, 0));
+       cl_git_pass(git_attr_file__new(&file, NULL, &source));
 
        cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz", true));
 
index 36beeb0954225fe3a245f24c781aee43dd79cc0e..eabc033eb97efac039f3851c196ae54c03ced181 100644 (file)
@@ -71,11 +71,11 @@ void test_attr_repo__get_one(void)
        }
 
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
 }
 
 void test_attr_repo__get_one_start_deep(void)
@@ -92,11 +92,11 @@ void test_attr_repo__get_one_start_deep(void)
        }
 
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
 }
 
 void test_attr_repo__get_many(void)
@@ -341,7 +341,7 @@ void test_attr_repo__sysdir_with_session(void)
        g_repo = cl_git_sandbox_reopen();
 
        cl_git_pass(git_attr_session__init(&session, g_repo));
-       cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, 0, "file", ARRAY_SIZE(attrs), attrs));
+       cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, NULL, "file", ARRAY_SIZE(attrs), attrs));
 
        cl_assert_equal_s(values[0], "1");
        cl_assert_equal_s(values[1], "2");
index f8d9abe552df469f74bf406ee928cf3e38ac6534..3241a3eb7672dbfe294ca0fc870833a95b63d3db 100644 (file)
@@ -1636,3 +1636,49 @@ void test_checkout_tree__no_index_refresh(void)
        modify_index_and_checkout_tree(&opts);
        assert_status_entrycount(g_repo, 0);
 }
+
+void test_checkout_tree__dry_run(void)
+{
+       git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+       git_oid oid;
+       git_object *obj = NULL;
+       checkout_counts ct;
+
+       /* first let's get things into a known state - by checkout out the HEAD */
+
+       assert_on_branch(g_repo, "master");
+
+       opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+       cl_git_pass(git_checkout_head(g_repo, &opts));
+
+       cl_assert(!git_path_isdir("testrepo/a"));
+
+       check_file_contents_nocr("testrepo/branch_file.txt", "hi\nbye!\n");
+
+       /* now checkout branch but with dry run enabled */
+
+       memset(&ct, 0, sizeof(ct));
+       opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DRY_RUN;
+       opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
+       opts.notify_cb = checkout_count_callback;
+       opts.notify_payload = &ct;
+
+       cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
+       cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY));
+
+       cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
+       cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir"));
+
+       assert_on_branch(g_repo, "dir");
+
+       /* these normally would have been created and updated, but with
+        * DRY_RUN they will be unchanged.
+        */
+       cl_assert(!git_path_isdir("testrepo/a"));
+       check_file_contents_nocr("testrepo/branch_file.txt", "hi\nbye!\n");
+
+       /* check that notify callback was invoked */
+       cl_assert_equal_i(ct.n_updates, 2);
+       
+       git_object_free(obj);
+}
index 31a536427872ca2d388805b5348d58cb81b73185..44ede457258a9385c6525587cfd6f3a2eeb1b48b 100644 (file)
@@ -8,6 +8,12 @@
 
 #ifdef _WIN32
 
+#ifdef CLAR_WIN32_LONGPATHS
+# define CLAR_MAX_PATH 4096
+#else
+# define CLAR_MAX_PATH MAX_PATH
+#endif
+
 #define RM_RETRY_COUNT 5
 #define RM_RETRY_DELAY 10
 
@@ -48,21 +54,48 @@ fs_rmdir_rmdir(WCHAR *_wpath)
        return 0;
 }
 
+static void translate_path(WCHAR *path, size_t path_size)
+{
+    size_t path_len, i;
+
+    if (wcsncmp(path, L"\\\\?\\", 4) == 0)
+       return;
+
+    path_len = wcslen(path);
+    cl_assert(path_size > path_len + 4);
+
+    for (i = path_len; i > 0; i--) {
+       WCHAR c = path[i - 1];
+
+       if (c == L'/')
+           path[i + 3] = L'\\';
+       else
+           path[i + 3] = path[i - 1];
+    }
+
+    path[0] = L'\\';
+    path[1] = L'\\';
+    path[2] = L'?';
+    path[3] = L'\\';
+    path[path_len + 4] = L'\0';
+}
+
 static void
 fs_rmdir_helper(WCHAR *_wsource)
 {
-       WCHAR buffer[MAX_PATH];
+       WCHAR buffer[CLAR_MAX_PATH];
        HANDLE find_handle;
        WIN32_FIND_DATAW find_data;
        size_t buffer_prefix_len;
 
        /* Set up the buffer and capture the length */
-       wcscpy_s(buffer, MAX_PATH, _wsource);
-       wcscat_s(buffer, MAX_PATH, L"\\");
+       wcscpy_s(buffer, CLAR_MAX_PATH, _wsource);
+       translate_path(buffer, CLAR_MAX_PATH);
+       wcscat_s(buffer, CLAR_MAX_PATH, L"\\");
        buffer_prefix_len = wcslen(buffer);
 
        /* FindFirstFile needs a wildcard to match multiple items */
-       wcscat_s(buffer, MAX_PATH, L"*");
+       wcscat_s(buffer, CLAR_MAX_PATH, L"*");
        find_handle = FindFirstFileW(buffer, &find_data);
        cl_assert(INVALID_HANDLE_VALUE != find_handle);
 
@@ -72,7 +105,7 @@ fs_rmdir_helper(WCHAR *_wsource)
                if (fs__dotordotdot(find_data.cFileName))
                        continue;
 
-               wcscpy_s(buffer + buffer_prefix_len, MAX_PATH - buffer_prefix_len, find_data.cFileName);
+               wcscpy_s(buffer + buffer_prefix_len, CLAR_MAX_PATH - buffer_prefix_len, find_data.cFileName);
 
                if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
                        fs_rmdir_helper(buffer);
@@ -123,7 +156,7 @@ fs_rm_wait(WCHAR *_wpath)
 static void
 fs_rm(const char *_source)
 {
-       WCHAR wsource[MAX_PATH];
+       WCHAR wsource[CLAR_MAX_PATH];
        DWORD attrs;
 
        /* The input path is UTF-8. Convert it to wide characters
@@ -133,7 +166,9 @@ fs_rm(const char *_source)
                                _source,
                                -1, /* Indicates NULL termination */
                                wsource,
-                               MAX_PATH));
+                               CLAR_MAX_PATH));
+
+       translate_path(wsource, CLAR_MAX_PATH);
 
        /* Does the item exist? If not, we have no work to do */
        attrs = GetFileAttributesW(wsource);
@@ -158,21 +193,23 @@ fs_rm(const char *_source)
 static void
 fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
 {
-       WCHAR buf_source[MAX_PATH], buf_dest[MAX_PATH];
+       WCHAR buf_source[CLAR_MAX_PATH], buf_dest[CLAR_MAX_PATH];
        HANDLE find_handle;
        WIN32_FIND_DATAW find_data;
        size_t buf_source_prefix_len, buf_dest_prefix_len;
 
-       wcscpy_s(buf_source, MAX_PATH, _wsource);
-       wcscat_s(buf_source, MAX_PATH, L"\\");
+       wcscpy_s(buf_source, CLAR_MAX_PATH, _wsource);
+       wcscat_s(buf_source, CLAR_MAX_PATH, L"\\");
+       translate_path(buf_source, CLAR_MAX_PATH);
        buf_source_prefix_len = wcslen(buf_source);
 
-       wcscpy_s(buf_dest, MAX_PATH, _wdest);
-       wcscat_s(buf_dest, MAX_PATH, L"\\");
+       wcscpy_s(buf_dest, CLAR_MAX_PATH, _wdest);
+       wcscat_s(buf_dest, CLAR_MAX_PATH, L"\\");
+       translate_path(buf_dest, CLAR_MAX_PATH);
        buf_dest_prefix_len = wcslen(buf_dest);
 
        /* Get an enumerator for the items in the source. */
-       wcscat_s(buf_source, MAX_PATH, L"*");
+       wcscat_s(buf_source, CLAR_MAX_PATH, L"*");
        find_handle = FindFirstFileW(buf_source, &find_data);
        cl_assert(INVALID_HANDLE_VALUE != find_handle);
 
@@ -185,8 +222,8 @@ fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
                if (fs__dotordotdot(find_data.cFileName))
                        continue;
 
-               wcscpy_s(buf_source + buf_source_prefix_len, MAX_PATH - buf_source_prefix_len, find_data.cFileName);
-               wcscpy_s(buf_dest + buf_dest_prefix_len, MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
+               wcscpy_s(buf_source + buf_source_prefix_len, CLAR_MAX_PATH - buf_source_prefix_len, find_data.cFileName);
+               wcscpy_s(buf_dest + buf_dest_prefix_len, CLAR_MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
 
                if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
                        fs_copydir_helper(buf_source, buf_dest);
@@ -205,7 +242,7 @@ fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
 static void
 fs_copy(const char *_source, const char *_dest)
 {
-       WCHAR wsource[MAX_PATH], wdest[MAX_PATH];
+       WCHAR wsource[CLAR_MAX_PATH], wdest[CLAR_MAX_PATH];
        DWORD source_attrs, dest_attrs;
        HANDLE find_handle;
        WIN32_FIND_DATAW find_data;
@@ -217,14 +254,17 @@ fs_copy(const char *_source, const char *_dest)
                                _source,
                                -1,
                                wsource,
-                               MAX_PATH));
+                               CLAR_MAX_PATH));
 
        cl_assert(MultiByteToWideChar(CP_UTF8,
                                MB_ERR_INVALID_CHARS,
                                _dest,
                                -1,
                                wdest,
-                               MAX_PATH));
+                               CLAR_MAX_PATH));
+
+       translate_path(wsource, CLAR_MAX_PATH);
+       translate_path(wdest, CLAR_MAX_PATH);
 
        /* Check the source for existence */
        source_attrs = GetFileAttributesW(wsource);
@@ -238,8 +278,8 @@ fs_copy(const char *_source, const char *_dest)
                 * Use FindFirstFile to parse the path */
                find_handle = FindFirstFileW(wsource, &find_data);
                cl_assert(INVALID_HANDLE_VALUE != find_handle);
-               wcscat_s(wdest, MAX_PATH, L"\\");
-               wcscat_s(wdest, MAX_PATH, find_data.cFileName);
+               wcscat_s(wdest, CLAR_MAX_PATH, L"\\");
+               wcscat_s(wdest, CLAR_MAX_PATH, find_data.cFileName);
                FindClose(find_handle);
 
                /* Check the new target for existence */
@@ -396,7 +436,7 @@ static void
 fs_copy(const char *source, const char *_dest)
 {
        char *dbuf = NULL;
-       const char *dest;
+       const char *dest = NULL;
        struct stat source_st, dest_st;
 
        cl_must_pass_(lstat(source, &source_st), "Failed to stat copy source");
index 2114819e4e77493bf0cf36952dc9883c3b4fea64..0ba1479620ab351e8fc9750f97fd840ada543637 100644 (file)
@@ -2,7 +2,7 @@
 #include <sys/syslimits.h>
 #endif
 
-static char _clar_path[4096];
+static char _clar_path[4096 + 1];
 
 static int
 is_valid_tmp_path(const char *path)
@@ -39,7 +39,8 @@ find_tmp_path(char *buffer, size_t length)
                        if (length >= PATH_MAX && realpath(env, buffer) != NULL)
                                return 0;
 #endif
-                       strncpy(buffer, env, length);
+                       strncpy(buffer, env, length - 1);
+                       buffer[length - 1] = '\0';
                        return 0;
                }
        }
@@ -50,7 +51,8 @@ find_tmp_path(char *buffer, size_t length)
                if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL)
                        return 0;
 #endif
-               strncpy(buffer, "/tmp", length);
+               strncpy(buffer, "/tmp", length - 1);
+               buffer[length - 1] = '\0';
                return 0;
        }
 
@@ -65,7 +67,8 @@ find_tmp_path(char *buffer, size_t length)
 
        /* This system doesn't like us, try to use the current directory */
        if (is_valid_tmp_path(".")) {
-               strncpy(buffer, ".", length);
+               strncpy(buffer, ".", length - 1);
+               buffer[length - 1] = '\0';
                return 0;
        }
 
index 65b8923f5cdb9c512f5269239f9385aedad7c53d..c4550c32a8bc581541dca5838937cbea1a064e41 100644 (file)
@@ -275,7 +275,7 @@ const char* cl_git_fixture_url(const char *fixturename)
 
 const char* cl_git_path_url(const char *path)
 {
-       static char url[4096];
+       static char url[4096 + 1];
 
        const char *in_buf;
        git_buf path_buf = GIT_BUF_INIT;
@@ -311,9 +311,10 @@ const char* cl_git_path_url(const char *path)
                in_buf++;
        }
 
-       cl_assert(url_buf.size < 4096);
+       cl_assert(url_buf.size < sizeof(url) - 1);
 
-       strncpy(url, git_buf_cstr(&url_buf), 4096);
+       strncpy(url, git_buf_cstr(&url_buf), sizeof(url) - 1);
+       url[sizeof(url) - 1] = '\0';
        git_buf_dispose(&url_buf);
        git_buf_dispose(&path_buf);
        return url;
index d4d8d2c37be4e06e721374c3c1f1d61960fb4eb0..8eb6d4e8dd96d41c9addf6f67bca3009c8df0a07 100644 (file)
@@ -164,7 +164,7 @@ void _cl_trace_cb__event_handler(
        switch (ev) {
        case CL_TRACE__SUITE_BEGIN:
                git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name);
-#if 0 && defined(GIT_MSVC_CRTDBG)
+#if 0 && defined(GIT_WIN32_LEAKCHECK)
                git_win32__crtdbg_stacktrace__dump(
                        GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
                        suite_name);
@@ -172,7 +172,7 @@ void _cl_trace_cb__event_handler(
                break;
 
        case CL_TRACE__SUITE_END:
-#if 0 && defined(GIT_MSVC_CRTDBG)
+#if 0 && defined(GIT_WIN32_LEAKCHECK)
                /* As an example of checkpointing, dump leaks within this suite.
                 * This may generate false positives for things like the global
                 * TLS error state and maybe the odb cache since they aren't
index 7ca49085cfe957402530425cdb391c8a20ec2b4d..ec12fee18a13a7d963362c97d347f0388fa47fd7 100644 (file)
@@ -158,6 +158,8 @@ void test_clone_nonetwork__can_prevent_the_checkout_of_a_standard_repo(void)
 
 void test_clone_nonetwork__can_checkout_given_branch(void)
 {
+       git_reference *remote_head;
+
        g_options.checkout_branch = "test";
        cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 
@@ -167,6 +169,12 @@ void test_clone_nonetwork__can_checkout_given_branch(void)
        cl_assert_equal_s(git_reference_name(g_ref), "refs/heads/test");
 
        cl_assert(git_path_exists("foo/readme.txt"));
+
+       cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD"));
+       cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head));
+       cl_assert_equal_s("refs/remotes/origin/master", git_reference_symbolic_target(remote_head));
+
+       git_reference_free(remote_head);
 }
 
 static int clone_cancel_fetch_transfer_progress_cb(
index e2b0fc96cf1477122f2e3be531f0b90f110a83ab..b702d62114057ac324b5d2c26ad424fc33e4a435 100644 (file)
@@ -178,6 +178,30 @@ void test_config_include__rewriting_include_refreshes_values(void)
        cl_git_pass(p_unlink("second"));
 }
 
+void test_config_include__rewriting_include_twice_refreshes_values(void)
+{
+       cl_git_mkfile("top-level", "[include]\npath = included");
+       cl_git_mkfile("included", "[foo]\nbar = first-value");
+
+       cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+       cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
+
+       git_buf_clear(&buf);
+       cl_git_mkfile("included", "[foo]\nother = value2");
+       cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar"));
+       cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.other"));
+       cl_assert_equal_s(buf.ptr, "value2");
+
+       git_buf_clear(&buf);
+       cl_git_mkfile("included", "[foo]\nanother = bar");
+       cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.other"));
+       cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.another"));
+       cl_assert_equal_s(buf.ptr, "bar");
+
+       cl_git_pass(p_unlink("top-level"));
+       cl_git_pass(p_unlink("included"));
+}
+
 void test_config_include__included_variables_cannot_be_deleted(void)
 {
        cl_git_mkfile("top-level", "[include]\npath = included\n");
index 10990875080f6ff95658a5071e612f477384be06..8d1bb8b0afa2c86b90b51e7ee99612c0c64cb317 100644 (file)
@@ -213,6 +213,13 @@ void test_config_read__symbol_headers(void)
        git_config_free(cfg);
 }
 
+void test_config_read__multiline_multiple_quoted_comment_chars(void)
+{
+       git_config *cfg;
+       cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config21")));
+       git_config_free(cfg);
+}
+
 void test_config_read__header_in_last_line(void)
 {
        git_config *cfg;
@@ -964,7 +971,7 @@ void test_config_read__get_mapped(void)
                                                                  "  key9 = off\n");
        cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
 
-       // check parsing bool and string
+       /* check parsing bool and string */
        cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map1, ARRAY_SIZE(_test_map1)));
        cl_assert_equal_i(val, MAP_TRUE);
        cl_git_pass(git_config_get_mapped(&val, cfg, "header.key2", _test_map1, ARRAY_SIZE(_test_map1)));
@@ -986,7 +993,7 @@ void test_config_read__get_mapped(void)
 
        cl_git_fail(git_config_get_mapped(&val, cfg, "header.key7", _test_map1, ARRAY_SIZE(_test_map1)));
 
-       // check parsing int values
+       /* check parsing int values */
        cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map2, ARRAY_SIZE(_test_map2)));
        cl_git_pass(git_config_get_int32(&known_good, cfg, "header.key1"));
        cl_assert_equal_i(val, known_good);
index 4e895afd97c12b5e33ffbd07d593ff0bd2fb6c86..2af4a87126b48ef6fdd06edb90d3041b0173e8b8 100644 (file)
@@ -1,6 +1,5 @@
 #include "clar_libgit2.h"
 #include "buffer.h"
-#include "buf_text.h"
 #include "git2/sys/hashsig.h"
 #include "futils.h"
 
@@ -633,7 +632,6 @@ void test_core_buffer__join3(void)
 void test_core_buffer__11(void)
 {
        git_buf a = GIT_BUF_INIT;
-       git_strarray t;
        char *t1[] = { "nothing", "in", "common" };
        char *t2[] = { "something", "something else", "some other" };
        char *t3[] = { "something", "some fun", "no fun" };
@@ -642,39 +640,25 @@ void test_core_buffer__11(void)
        char *t6[] = { "no", "nope", "" };
        char *t7[] = { "", "doesn't matter" };
 
-       t.strings = t1;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t1, 3));
        cl_assert_equal_s(a.ptr, "");
 
-       t.strings = t2;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t2, 3));
        cl_assert_equal_s(a.ptr, "some");
 
-       t.strings = t3;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t3, 3));
        cl_assert_equal_s(a.ptr, "");
 
-       t.strings = t4;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t4, 3));
        cl_assert_equal_s(a.ptr, "happ");
 
-       t.strings = t5;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t5, 3));
        cl_assert_equal_s(a.ptr, "happ");
 
-       t.strings = t6;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t6, 3));
        cl_assert_equal_s(a.ptr, "");
 
-       t.strings = t7;
-       t.count = 3;
-       cl_git_pass(git_buf_text_common_prefix(&a, &t));
+       cl_git_pass(git_buf_common_prefix(&a, t7, 3));
        cl_assert_equal_s(a.ptr, "");
 
        git_buf_dispose(&a);
@@ -709,19 +693,19 @@ void test_core_buffer__puts_escaped(void)
        git_buf a = GIT_BUF_INIT;
 
        git_buf_clear(&a);
-       cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "", ""));
+       cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "", ""));
        cl_assert_equal_s("this is a test", a.ptr);
 
        git_buf_clear(&a);
-       cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "t", "\\"));
+       cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "t", "\\"));
        cl_assert_equal_s("\\this is a \\tes\\t", a.ptr);
 
        git_buf_clear(&a);
-       cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "i ", "__"));
+       cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "i ", "__"));
        cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr);
 
        git_buf_clear(&a);
-       cl_git_pass(git_buf_text_puts_escape_regex(&a, "^match\\s*[A-Z]+.*"));
+       cl_git_pass(git_buf_puts_escape_regex(&a, "^match\\s*[A-Z]+.*"));
        cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr);
 
        git_buf_dispose(&a);
@@ -731,7 +715,7 @@ static void assert_unescape(char *expected, char *to_unescape) {
        git_buf buf = GIT_BUF_INIT;
 
        cl_git_pass(git_buf_sets(&buf, to_unescape));
-       git_buf_text_unescape(&buf);
+       git_buf_unescape(&buf);
        cl_assert_equal_s(expected, buf.ptr);
        cl_assert_equal_sz(strlen(expected), buf.size);
 
@@ -864,20 +848,20 @@ void test_core_buffer__classify_with_utf8(void)
        git_buf b;
 
        b.ptr = data0; b.size = b.asize = data0len;
-       cl_assert(!git_buf_text_is_binary(&b));
-       cl_assert(!git_buf_text_contains_nul(&b));
+       cl_assert(!git_buf_is_binary(&b));
+       cl_assert(!git_buf_contains_nul(&b));
 
        b.ptr = data1; b.size = b.asize = data1len;
-       cl_assert(!git_buf_text_is_binary(&b));
-       cl_assert(!git_buf_text_contains_nul(&b));
+       cl_assert(!git_buf_is_binary(&b));
+       cl_assert(!git_buf_contains_nul(&b));
 
        b.ptr = data2; b.size = b.asize = data2len;
-       cl_assert(git_buf_text_is_binary(&b));
-       cl_assert(git_buf_text_contains_nul(&b));
+       cl_assert(git_buf_is_binary(&b));
+       cl_assert(git_buf_contains_nul(&b));
 
        b.ptr = data3; b.size = b.asize = data3len;
-       cl_assert(!git_buf_text_is_binary(&b));
-       cl_assert(!git_buf_text_contains_nul(&b));
+       cl_assert(!git_buf_is_binary(&b));
+       cl_assert(!git_buf_contains_nul(&b));
 }
 
 #define SIMILARITY_TEST_DATA_1 \
@@ -1074,80 +1058,80 @@ void test_core_buffer__lf_and_crlf_conversions(void)
 
        git_buf_sets(&src, "lf\nlf\nlf\nlf\n");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("lf\r\nlf\r\nlf\r\nlf\r\n", tgt);
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(src.ptr, tgt);
 
        git_buf_sets(&src, "\nlf\nlf\nlf\nlf\nlf");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("\r\nlf\r\nlf\r\nlf\r\nlf\r\nlf", tgt);
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(src.ptr, tgt);
 
        /* CRLF source */
 
        git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n", tgt);
 
        git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n");
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt);
 
        git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf", tgt);
 
        git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf");
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt);
 
        /* CRLF in LF text */
 
        git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("\r\nlf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\ncrlf\r\n", tgt);
 
        git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n");
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt);
 
        /* LF in CRLF text */
 
        git_buf_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("\r\ncrlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf", tgt);
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt);
 
        /* bare CR test */
 
        git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r");
 
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf("\rcrlf\r\nlf\r\nlf\r\ncr\rcrlf\r\nlf\r\ncr\r", tgt);
 
        git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r");
 
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt);
 
        git_buf_sets(&src, "\rcr\r");
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf(src.ptr, tgt);
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf("\rcr\r", tgt);
 
        git_buf_dispose(&src);
@@ -1156,37 +1140,37 @@ void test_core_buffer__lf_and_crlf_conversions(void)
        /* blob correspondence tests */
 
        git_buf_sets(&src, ALL_CRLF_TEXT_RAW);
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf(ALL_CRLF_TEXT_AS_CRLF, tgt);
        git_buf_sets(&src, ALL_CRLF_TEXT_RAW);
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(ALL_CRLF_TEXT_AS_LF, tgt);
        git_buf_dispose(&src);
        git_buf_dispose(&tgt);
 
        git_buf_sets(&src, ALL_LF_TEXT_RAW);
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf(ALL_LF_TEXT_AS_CRLF, tgt);
        git_buf_sets(&src, ALL_LF_TEXT_RAW);
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(ALL_LF_TEXT_AS_LF, tgt);
        git_buf_dispose(&src);
        git_buf_dispose(&tgt);
 
        git_buf_sets(&src, MORE_CRLF_TEXT_RAW);
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf(MORE_CRLF_TEXT_AS_CRLF, tgt);
        git_buf_sets(&src, MORE_CRLF_TEXT_RAW);
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(MORE_CRLF_TEXT_AS_LF, tgt);
        git_buf_dispose(&src);
        git_buf_dispose(&tgt);
 
        git_buf_sets(&src, MORE_LF_TEXT_RAW);
-       cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+       cl_git_pass(git_buf_lf_to_crlf(&tgt, &src));
        check_buf(MORE_LF_TEXT_AS_CRLF, tgt);
        git_buf_sets(&src, MORE_LF_TEXT_RAW);
-       cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+       cl_git_pass(git_buf_crlf_to_lf(&tgt, &src));
        check_buf(MORE_LF_TEXT_AS_LF, tgt);
        git_buf_dispose(&src);
        git_buf_dispose(&tgt);
index a677afe2e92817a2c7bebdcb6248d9bc96796bc6..6cec24679dcd6fda764432fd8767c66c5fd7da40 100644 (file)
@@ -14,7 +14,7 @@ void test_core_encoding__decode(void)
        cl_assert(size == 4);
 
        buf = (unsigned char *)"\xaa\xaa\xfe\xdc\xbaXY";
-       cl_assert(git_decode_varint(buf, &size) == 1489279344088ULL);
+       cl_assert(git_decode_varint(buf, &size) == UINT64_C(1489279344088));
        cl_assert(size == 6);
 
        buf = (unsigned char *)"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xfe\xdc\xbaXY";
@@ -35,8 +35,8 @@ void test_core_encoding__encode(void)
        cl_assert(git_encode_varint(buf, 100, 267869656) == 4);
        cl_assert(!memcmp(buf, "\xfe\xdc\xbaX", 4));
 
-       cl_assert(git_encode_varint(buf, 100, 1489279344088ULL) == 6);
+       cl_assert(git_encode_varint(buf, 100, UINT64_C(1489279344088)) == 6);
        cl_assert(!memcmp(buf, "\xaa\xaa\xfe\xdc\xbaX", 6));
 
-       cl_assert(git_encode_varint(buf, 1, 1489279344088ULL) == -1);
+       cl_assert(git_encode_varint(buf, 1, UINT64_C(1489279344088)) == -1);
 }
diff --git a/tests/core/integer.c b/tests/core/integer.c
new file mode 100644 (file)
index 0000000..18364ba
--- /dev/null
@@ -0,0 +1,253 @@
+#include "clar_libgit2.h"
+
+void test_core_integer__multiply_int64_no_overflow(void)
+{
+#if !defined(git__multiply_int64_overflow)
+       int64_t result = 0;
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x0), INT64_C(-0x8000000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x1));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x1));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x1));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x1));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x7fffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(0x4));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x4));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x2));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x4));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(0x4));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(-0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x7ffffffffffffff)));
+       cl_assert_equal_i(result, INT64_C(0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x800000000000000)));
+       cl_assert_equal_i(result, INT64_C(0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x4000000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x8000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(-0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x7ffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(-0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(0xffffffffffffffe));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x800000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x2)));
+       cl_assert_equal_i(result, INT64_C(0x1000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x4000000000000000), INT64_C(0x2)));
+       cl_assert_equal_i(result, INT64_C(-0x8000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(0x7fffffffffffffff));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x0)));
+       cl_assert_equal_i(result, INT64_C(0x0));
+#endif
+}
+
+void test_core_integer__multiply_int64_overflow(void)
+{
+#if !defined(git__multiply_int64_overflow)
+       int64_t result = 0;
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x4000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x2), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x2), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7ffffffffffffff), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7ffffffffffffff), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x800000000000000), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x800000000000000), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x4000000000000000), INT64_C(0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x7fffffffffffffff), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x7fffffffffffffff), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x2)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x7ffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x800000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x7fffffffffffffff)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x8000000000000000)));
+#endif
+}
+
+void test_core_integer__multiply_int64_edge_cases(void)
+{
+#if !defined(git__multiply_int64_overflow)
+       int64_t result = 0;
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(-0x1)));
+       cl_assert_equal_i(result, INT64_C(-0x8000000000000000));
+       cl_assert(!git__multiply_int64_overflow(&result, INT64_C(-0x1), INT64_C(-0x8000000000000000)));
+       cl_assert_equal_i(result, INT64_C(-0x8000000000000000));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(0x1), INT64_C(-0x8000000000000000)));
+       cl_assert(git__multiply_int64_overflow(&result, INT64_C(-0x8000000000000000), INT64_C(0x1)));
+#endif
+}
index 1e5ed454cc4ea84376b1ca1072efbe759b3c1ab3..0493edf1dd7358375f4877f22aa9622c249fcc56 100644 (file)
@@ -123,7 +123,7 @@ static void do_junction(const char *old, const char *new)
        reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
        cl_assert(reparse_buf);
 
-       subst_utf16 = reparse_buf->MountPointReparseBuffer.PathBuffer;
+       subst_utf16 = reparse_buf->ReparseBuffer.MountPoint.PathBuffer;
        print_utf16 = subst_utf16 + subst_utf16_len + 1;
 
        ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1,
@@ -135,10 +135,10 @@ static void do_junction(const char *old, const char *new)
        cl_assert_equal_i(print_utf16_len, ret);
 
        reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
-       reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0;
-       reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len;
-       reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
-       reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len;
+       reparse_buf->ReparseBuffer.MountPoint.SubstituteNameOffset = 0;
+       reparse_buf->ReparseBuffer.MountPoint.SubstituteNameLength = subst_byte_len;
+       reparse_buf->ReparseBuffer.MountPoint.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
+       reparse_buf->ReparseBuffer.MountPoint.PrintNameLength = print_byte_len;
        reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE;
 
        cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
index 72408cbe82148cb4df99afc9f9d9b28c9d4880e1..e8f65d51017ad1a6fa12583cf9bfbbb63d901a4c 100644 (file)
@@ -1,6 +1,11 @@
 #include "clar_libgit2.h"
 #include "cache.h"
 
+void test_core_opts__cleanup(void)
+{
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, NULL, 0));
+}
+
 void test_core_opts__readwrite(void)
 {
        size_t old_val = 0;
@@ -23,3 +28,44 @@ void test_core_opts__invalid_option(void)
        cl_git_fail(git_libgit2_opts(-1, "foobar"));
 }
 
+void test_core_opts__extensions_query(void)
+{
+       git_strarray out = { 0 };
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
+
+       cl_assert_equal_sz(out.count, 1);
+       cl_assert_equal_s("noop", out.strings[0]);
+
+       git_strarray_dispose(&out);
+}
+
+void test_core_opts__extensions_add(void)
+{
+       const char *in[] = { "foo" };
+       git_strarray out = { 0 };
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
+       cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
+
+       cl_assert_equal_sz(out.count, 2);
+       cl_assert_equal_s("noop", out.strings[0]);
+       cl_assert_equal_s("foo", out.strings[1]);
+
+       git_strarray_dispose(&out);
+}
+
+void test_core_opts__extensions_remove(void)
+{
+       const char *in[] = { "bar", "!negate", "!noop", "baz" };
+       git_strarray out = { 0 };
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
+       cl_git_pass(git_libgit2_opts(GIT_OPT_GET_EXTENSIONS, &out));
+
+       cl_assert_equal_sz(out.count, 2);
+       cl_assert_equal_s("bar", out.strings[0]);
+       cl_assert_equal_s("baz", out.strings[1]);
+
+       git_strarray_dispose(&out);
+}
index 2e5a4ab24c8a865e4340aece47ded7695c1a8d3c..eac3573fea7edc4f453725e7791285a81e7619c0 100644 (file)
@@ -31,15 +31,6 @@ check_basename(const char *A, const char *B)
        git__free(base2);
 }
 
-static void
-check_topdir(const char *A, const char *B)
-{
-       const char *dir;
-
-       cl_assert((dir = git_path_topdir(A)) != NULL);
-       cl_assert_equal_s(B, dir);
-}
-
 static void
 check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
 {
@@ -119,23 +110,6 @@ void test_core_path__01_basename(void)
        check_basename(REP1024("/abc"), "abc");
 }
 
-/* get the latest component in a path */
-void test_core_path__02_topdir(void)
-{
-       check_topdir(".git/", ".git/");
-       check_topdir("/.git/", ".git/");
-       check_topdir("usr/local/.git/", ".git/");
-       check_topdir("./.git/", ".git/");
-       check_topdir("/usr/.git/", ".git/");
-       check_topdir("/", "/");
-       check_topdir("a/", "a/");
-
-       cl_assert(git_path_topdir("/usr/.git") == NULL);
-       cl_assert(git_path_topdir(".") == NULL);
-       cl_assert(git_path_topdir("") == NULL);
-       cl_assert(git_path_topdir("a") == NULL);
-}
-
 /* properly join path components */
 void test_core_path__05_joins(void)
 {
@@ -285,7 +259,7 @@ void test_core_path__08_self_join(void)
        cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc"));
        cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc");
        cl_assert(asize < path.asize);
-       
+
        git_buf_dispose(&path);
 }
 
index f81d40854481fc025e82372e4bc51b386861f2e8..196b003525fea9b6169f7ea1a56afb9710f5e581 100644 (file)
@@ -52,7 +52,7 @@ void test_core_sha1__detect_collision_attack(void)
        git_oid oid, expected;
 
 #ifdef GIT_SHA1_COLLISIONDETECT
-       GIT_UNUSED(expected);
+       GIT_UNUSED(&expected);
        cl_git_fail(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf"));
        cl_assert_equal_s("SHA1 collision attack detected", git_error_last()->message);
 #else
index 35e92ece9ce09f450ddbfb46f764863aeb64d3d2..d5bbcea19f22568a798bb57ad73db6872327269c 100644 (file)
@@ -54,7 +54,7 @@ void test_core_sortedcache__name_only(void)
        cl_assert_equal_i(
                GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "abc"));
 
-       git_sortedcache_clear(sc, true);
+       cl_git_pass(git_sortedcache_clear(sc, true));
 
        cl_assert_equal_sz(0, git_sortedcache_entrycount(sc));
        cl_assert(git_sortedcache_entry(sc, 0) == NULL);
@@ -154,7 +154,7 @@ void test_core_sortedcache__in_memory(void)
 
        cl_assert_equal_i(0, free_count);
 
-       git_sortedcache_clear(sc, true);
+       cl_git_pass(git_sortedcache_clear(sc, true));
 
        cl_assert_equal_i(5, free_count);
 
@@ -247,7 +247,7 @@ static void sortedcache_test_reload(git_sortedcache *sc)
 
        cl_assert(git_sortedcache_lockandload(sc, &buf) > 0);
 
-       git_sortedcache_clear(sc, false); /* clear once we already have lock */
+       cl_git_pass(git_sortedcache_clear(sc, false)); /* clear once we already have lock */
 
        for (scan = buf.ptr; *scan; scan = after + 1) {
                int val = strtol(scan, &after, 0);
index 85db0c6623008a7e92015f511c4b2a7696412bb2..928dfbcc1fcd6dd3183da6933ad45174fc613485 100644 (file)
@@ -123,3 +123,14 @@ void test_core_string__strcasecmp(void)
        cl_assert(git__strcasecmp("et", "e\342\202\254ghi=") < 0);
        cl_assert(git__strcasecmp("\303\215", "\303\255") < 0);
 }
+
+void test_core_string__strlcmp(void)
+{
+       const char foo[3] = { 'f', 'o', 'o' };
+
+       cl_assert(git__strlcmp("foo", "foo", 3) == 0);
+       cl_assert(git__strlcmp("foo", foo, 3) == 0);
+       cl_assert(git__strlcmp("foo", "foobar", 3) == 0);
+       cl_assert(git__strlcmp("foobar", "foo", 3) > 0);
+       cl_assert(git__strlcmp("foo", "foobar", 6) < 0);
+}
index 25dbe467c1dd966d60e4eebbb9e48fc8cd1cacae..851b91b0a40c31b2f3d089fb687f35ed105f6ad0 100644 (file)
@@ -30,8 +30,9 @@ void test_core_strtol__int32(void)
 {
        assert_l32_parses("123", 123, 10);
        assert_l32_parses("  +123 ", 123, 10);
+       assert_l32_parses("  -123 ", -123, 10);
        assert_l32_parses("  +2147483647 ", 2147483647, 10);
-       assert_l32_parses("  -2147483648 ", -2147483648LL, 10);
+       assert_l32_parses("  -2147483648 ", INT64_C(-2147483648), 10);
        assert_l32_parses("A", 10, 16);
        assert_l32_parses("1x1", 1, 10);
 
@@ -46,10 +47,11 @@ void test_core_strtol__int64(void)
 {
        assert_l64_parses("123", 123, 10);
        assert_l64_parses("  +123 ", 123, 10);
+       assert_l64_parses("  -123 ", -123, 10);
        assert_l64_parses("  +2147483647 ", 2147483647, 10);
-       assert_l64_parses("  -2147483648 ", -2147483648LL, 10);
-       assert_l64_parses("  2147483657 ", 2147483657LL, 10);
-       assert_l64_parses("  -2147483657 ", -2147483657LL, 10);
+       assert_l64_parses("  -2147483648 ", INT64_C(-2147483648), 10);
+       assert_l64_parses("  2147483657 ", INT64_C(2147483657), 10);
+       assert_l64_parses("  -2147483657 ", INT64_C(-2147483657), 10);
        assert_l64_parses(" 9223372036854775807  ", INT64_MAX, 10);
        assert_l64_parses("   -9223372036854775808  ", INT64_MIN, 10);
        assert_l64_parses("   0x7fffffffffffffff  ", INT64_MAX, 16);
index 192096be3f8502c64b424db3481945eeec167a79..d24da874da59f08d167e0dec38693dbe75dade19 100644 (file)
@@ -1,4 +1,5 @@
 #include "clar_libgit2.h"
+#include <git2/sys/commit_graph.h>
 #include <git2/sys/config.h>
 #include <git2/sys/filter.h>
 #include <git2/sys/odb_backend.h>
@@ -82,6 +83,11 @@ void test_core_structinit__compare(void)
                git_blame_options, GIT_BLAME_OPTIONS_VERSION, \
                GIT_BLAME_OPTIONS_INIT, git_blame_options_init);
 
+       /* blob_filter_options */
+       CHECK_MACRO_FUNC_INIT_EQUAL( \
+               git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_VERSION, \
+               GIT_BLOB_FILTER_OPTIONS_INIT, git_blob_filter_options_init);
+
        /* checkout */
        CHECK_MACRO_FUNC_INIT_EQUAL( \
                git_checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, \
@@ -92,6 +98,13 @@ void test_core_structinit__compare(void)
                git_clone_options, GIT_CLONE_OPTIONS_VERSION, \
                GIT_CLONE_OPTIONS_INIT, git_clone_options_init);
 
+       /* commit_graph_writer */
+       CHECK_MACRO_FUNC_INIT_EQUAL( \
+               git_commit_graph_writer_options, \
+               GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION, \
+               GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT, \
+               git_commit_graph_writer_options_init);
+
        /* diff */
        CHECK_MACRO_FUNC_INIT_EQUAL( \
                git_diff_options, GIT_DIFF_OPTIONS_VERSION, \
index c6c5220b2b2ea35e7d635925ca12ff5718798462..2ce935bf5466e6c2b28edaa354f19975c551c42b 100644 (file)
@@ -1,5 +1,5 @@
 #include "clar_libgit2.h"
-#include "global.h"
+#include "settings.h"
 
 void test_core_useragent__get(void)
 {
diff --git a/tests/core/utf8.c b/tests/core/utf8.c
new file mode 100644 (file)
index 0000000..021828e
--- /dev/null
@@ -0,0 +1,19 @@
+#include "clar_libgit2.h"
+
+void test_core_utf8__char_length(void)
+{
+       cl_assert_equal_i(0, git_utf8_char_length("", 0));
+       cl_assert_equal_i(1, git_utf8_char_length("$", 1));
+       cl_assert_equal_i(5, git_utf8_char_length("abcde", 5));
+       cl_assert_equal_i(1, git_utf8_char_length("\xc2\xa2", 2));
+       cl_assert_equal_i(2, git_utf8_char_length("\x24\xc2\xa2", 3));
+       cl_assert_equal_i(1, git_utf8_char_length("\xf0\x90\x8d\x88", 4));
+
+       /* uncontinued character counted as single characters */
+       cl_assert_equal_i(2, git_utf8_char_length("\x24\xc2", 2));
+       cl_assert_equal_i(3, git_utf8_char_length("\x24\xc2\xc2\xa2", 4));
+
+       /* invalid characters are counted as single characters */
+       cl_assert_equal_i(4, git_utf8_char_length("\x24\xc0\xc0\x34", 4));
+       cl_assert_equal_i(4, git_utf8_char_length("\x24\xf5\xfd\xc2", 4));
+}
index a7e1a03257c68617e8be1ace39d67674ec308501..08cd2c19bf99798ab6bacb6080ffe5497f9dc1cd 100644 (file)
@@ -8,7 +8,7 @@ void test_core_vector__0(void)
 {
        git_vector x;
        int i;
-       git_vector_init(&x, 1, NULL);
+       cl_git_pass(git_vector_init(&x, 1, NULL));
        for (i = 0; i < 10; ++i) {
                git_vector_insert(&x, (void*) 0xabc);
        }
@@ -21,7 +21,7 @@ void test_core_vector__1(void)
 {
        git_vector x;
        /* make initial capacity exact for our insertions. */
-       git_vector_init(&x, 3, NULL);
+       cl_git_pass(git_vector_init(&x, 3, NULL));
        git_vector_insert(&x, (void*) 0xabc);
        git_vector_insert(&x, (void*) 0xdef);
        git_vector_insert(&x, (void*) 0x123);
@@ -76,7 +76,7 @@ void test_core_vector__3(void)
 {
        git_vector x;
        intptr_t i;
-       git_vector_init(&x, 1, &compare_them);
+       cl_git_pass(git_vector_init(&x, 1, &compare_them));
 
        for (i = 0; i < 10; i += 2) {
                git_vector_insert_sorted(&x, (void*)(i + 1), NULL);
@@ -99,7 +99,7 @@ void test_core_vector__4(void)
 {
        git_vector x;
        intptr_t i;
-       git_vector_init(&x, 1, &compare_them);
+       cl_git_pass(git_vector_init(&x, 1, &compare_them));
 
        for (i = 0; i < 10; i += 2) {
                git_vector_insert_sorted(&x, (void*)(i + 1), NULL);
@@ -163,7 +163,7 @@ void test_core_vector__5(void)
        git_vector x;
        int i;
 
-       git_vector_init(&x, 1, &compare_structs);
+       cl_git_pass(git_vector_init(&x, 1, &compare_structs));
 
        for (i = 0; i < 10; i += 2)
                git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs);
@@ -205,7 +205,7 @@ void test_core_vector__remove_matching(void)
        size_t i;
        void *compare;
 
-       git_vector_init(&x, 1, NULL);
+       cl_git_pass(git_vector_init(&x, 1, NULL));
        git_vector_insert(&x, (void*) 0x001);
 
        cl_assert(x.length == 1);
index bdfc4cac32609e869a84aae15303096355948340..ea7aa070fa252f862e244c3d38a8bc149a32b52e 100644 (file)
@@ -18,6 +18,7 @@ void test_diff_format_email__cleanup(void)
        cl_git_sandbox_cleanup();
 }
 
+#ifndef GIT_DEPRECATE_HARD
 static void assert_email_match(
        const char *expected,
        const char *oidstr,
@@ -51,9 +52,11 @@ static void assert_email_match(
        git_commit_free(commit);
        git_buf_dispose(&buf);
 }
+#endif
 
 void test_diff_format_email__simple(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \
@@ -96,10 +99,12 @@ void test_diff_format_email__simple(void)
 
        assert_email_match(
                email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+#endif
 }
 
 void test_diff_format_email__with_message(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email = "From 627e7e12d87e07a83fad5b6bfa25e86ead4a5270 Mon Sep 17 00:00:00 2001\n" \
        "From: Patrick Steinhardt <ps@pks.im>\n" \
@@ -136,11 +141,13 @@ void test_diff_format_email__with_message(void)
 
        assert_email_match(
                email, "627e7e12d87e07a83fad5b6bfa25e86ead4a5270", &opts);
+#endif
 }
 
 
 void test_diff_format_email__multiple(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_oid oid;
        git_commit *commit = NULL;
        git_diff *diff = NULL;
@@ -256,10 +263,12 @@ void test_diff_format_email__multiple(void)
        git_diff_free(diff);
        git_commit_free(commit);
        git_buf_dispose(&buf);
+#endif
 }
 
 void test_diff_format_email__exclude_marker(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \
@@ -304,10 +313,12 @@ void test_diff_format_email__exclude_marker(void)
 
        assert_email_match(
                email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+#endif
 }
 
 void test_diff_format_email__invalid_no(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_oid oid;
        git_commit *commit = NULL;
        git_diff *diff = NULL;
@@ -327,15 +338,16 @@ void test_diff_format_email__invalid_no(void)
        cl_git_pass(git_diff__commit(&diff, repo, commit, NULL));
        cl_git_fail(git_diff_format_email(&buf, diff, &opts));
        cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 2, 1, 0, NULL));
-       cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 0, 0, 0, NULL));
 
        git_diff_free(diff);
        git_commit_free(commit);
        git_buf_dispose(&buf);
+#endif
 }
 
 void test_diff_format_email__mode_change(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 7ade76dd34bba4733cf9878079f9fd4a456a9189 Mon Sep 17 00:00:00 2001\n" \
@@ -357,10 +369,12 @@ void test_diff_format_email__mode_change(void)
 
        assert_email_match(
                email, "7ade76dd34bba4733cf9878079f9fd4a456a9189", &opts);
+#endif
 }
 
 void test_diff_format_email__rename_add_remove(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \
@@ -427,10 +441,12 @@ void test_diff_format_email__rename_add_remove(void)
 
        assert_email_match(
                email, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d", &opts);
+#endif
 }
 
 void test_diff_format_email__multiline_summary(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \
@@ -475,10 +491,12 @@ void test_diff_format_email__multiline_summary(void)
 
        assert_email_match(
                email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+#endif
 }
 
 void test_diff_format_email__binary(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
        const char *email =
        "From 8d7523f6fcb2404257889abe0d96f093d9f524f9 Mon Sep 17 00:00:00 2001\n" \
@@ -501,5 +519,6 @@ void test_diff_format_email__binary(void)
 
        assert_email_match(
                email, "8d7523f6fcb2404257889abe0d96f093d9f524f9", &opts);
+#endif
 }
 
index 7eb353627add3c59510f414e475a8968634b919b..d288bba58aab090b913537ab68c2445f5235a9c5 100644 (file)
@@ -4,7 +4,6 @@
 #include "diff_helpers.h"
 #include "diff.h"
 #include "repository.h"
-#include "buf_text.h"
 
 static git_repository *g_repo = NULL;
 
index df32eebf247d0283eaae9777275c1af100eea82e..bd25d29aaba782a35fe1e79a5ffa8e731e878f65 100644 (file)
@@ -1,6 +1,5 @@
 #include "clar_libgit2.h"
 #include "diff_helpers.h"
-#include "buf_text.h"
 
 static git_repository *g_repo = NULL;
 
@@ -22,6 +21,8 @@ void test_diff_rename__cleanup(void)
 #define RENAME_MODIFICATION_COMMIT "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"
 #define REWRITE_DELETE_COMMIT "84d8efa38af7ace2b302de0adbda16b1f1cd2e1b"
 #define DELETE_RENAME_COMMIT "be053a189b0bbde545e0a3f59ce00b46ad29ce0d"
+#define BREAK_REWRITE_BASE_COMMIT "db98035f715427eef1f5e17f03e1801c05301e9e"
+#define BREAK_REWRITE_COMMIT "7e7bfb88ba9bc65fd700fee1819cf1c317aafa56"
 
 /*
  * Renames repo has:
@@ -513,7 +514,7 @@ void test_diff_rename__working_directory_changes(void)
        cl_git_pass(
                git_futils_readbuffer(&old_content, "renames/songof7cities.txt"));
        cl_git_pass(
-               git_buf_text_lf_to_crlf(&content, &old_content));
+               git_buf_lf_to_crlf(&content, &old_content));
        cl_git_pass(
                git_futils_writebuffer(&content, "renames/songof7cities.txt", 0, 0));
 
@@ -1978,3 +1979,56 @@ void test_diff_rename__delete_and_rename(void)
        git_tree_free(old_tree);
        git_tree_free(new_tree);
 }
+
+/*
+ * The break_rewrite branch contains a testcase reduced from
+ * a real-world scenario, rather than being "constructed" like
+ * the above tests seem to be. There are two commits layered
+ * on top of the repo's initial commit; the base commit which
+ * clears out the files from the initial commit and installs
+ * four files. And then there's the modification commit which
+ * mutates the files in such a way as to trigger the bug in
+ * libgit2.
+ * commit db98035f715427eef1f5e17f03e1801c05301e9e
+ *   serving.txt     (deleted)
+ *   sevencities.txt (deleted)
+ *   AAA             (313 lines)
+ *   BBB             (314 lines)
+ *   CCC             (704 lines)
+ *   DDD             (314 lines, identical to BBB)
+ * commit 7e7bfb88ba9bc65fd700fee1819cf1c317aafa56
+ *   This deletes CCC and makes slight modifications
+ *   to AAA, BBB, and DDD. The find_best_matches loop
+ *   for git_diff_find_similar computes the following:
+ *   CCC    moved to    AAA     (similarity 91)
+ *   CCC    copied to   AAA     (similarity 91)
+ *   DDD    moved to    BBB     (similarity 52)
+ *   CCC    copied to   BBB     (similarity 90)
+ *   BBB    moved to    DDD     (similarity 52)
+ *   CCC    copied to   DDD     (similarity 90)
+ * The code to rewrite the diffs by resolving these
+ * copies/renames would resolve the BBB <-> DDD moves
+ * but then still leave BBB as a rename target for
+ * the deleted file CCC. Since the split flag on BBB
+ * was cleared, this would trigger an error.
+ */
+void test_diff_rename__break_rewrite(void)
+{
+       const char *old_sha = BREAK_REWRITE_BASE_COMMIT;
+       const char *new_sha = BREAK_REWRITE_COMMIT;
+       git_tree *old_tree, *new_tree;
+       git_diff *diff;
+       git_diff_find_options find_opts = GIT_DIFF_FIND_OPTIONS_INIT;
+
+       old_tree = resolve_commit_oid_to_tree(g_repo, old_sha);
+       new_tree = resolve_commit_oid_to_tree(g_repo, new_sha);
+
+       find_opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES | GIT_DIFF_BREAK_REWRITES | GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
+
+       cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, old_tree, new_tree, NULL));
+       cl_git_pass(git_diff_find_similar(diff, &find_opts));
+
+       git_diff_free(diff);
+       git_tree_free(old_tree);
+       git_tree_free(new_tree);
+}
index f2404958eb51497c10aede7e87aadf80aefcf05d..00c52ff1b4c2c007fb313ce05755dcc6e245921b 100644 (file)
@@ -2203,3 +2203,38 @@ void test_diff_workdir__order(void)
        git_diff_free(diff);
        git_tree_free(tree);
 }
+
+void test_diff_workdir__ignore_blank_lines(void)
+{
+       git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+       git_diff *diff;
+       git_patch *patch;
+       git_buf buf = GIT_BUF_INIT;
+
+       g_repo = cl_git_sandbox_init("rebase");
+       cl_git_rewritefile("rebase/gravy.txt", "GRAVY SOUP.\n\n\nGet eight pounds of coarse lean beef--wash it clean and lay it in your\n\npot, put in the same ingredients as for the shin soup, with the same\nquantity of water, and follow the process directed for that. Strain the\nsoup through a sieve, and serve it up clear, with nothing more than\ntoasted bread in it; two table-spoonsful of mushroom catsup will add a\nfine flavour to the soup!\n");
+
+       /* Perform the diff normally */
+       cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+       cl_git_pass(git_patch_from_diff(&patch, diff, 0));
+       cl_git_pass(git_patch_to_buf(&buf, patch));
+
+       cl_assert_equal_s("diff --git a/gravy.txt b/gravy.txt\nindex c4e6cca..3c617e6 100644\n--- a/gravy.txt\n+++ b/gravy.txt\n@@ -1,8 +1,10 @@\n GRAVY SOUP.\n \n+\n Get eight pounds of coarse lean beef--wash it clean and lay it in your\n+\n pot, put in the same ingredients as for the shin soup, with the same\n quantity of water, and follow the process directed for that. Strain the\n soup through a sieve, and serve it up clear, with nothing more than\n toasted bread in it; two table-spoonsful of mushroom catsup will add a\n-fine flavour to the soup.\n+fine flavour to the soup!\n", buf.ptr);
+
+       git_buf_dispose(&buf);
+       git_patch_free(patch);
+       git_diff_free(diff);
+
+       /* Perform the diff ignoring blank lines */
+       opts.flags |= GIT_DIFF_IGNORE_BLANK_LINES;
+
+       cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+       cl_git_pass(git_patch_from_diff(&patch, diff, 0));
+       cl_git_pass(git_patch_to_buf(&buf, patch));
+
+       cl_assert_equal_s("diff --git a/gravy.txt b/gravy.txt\nindex c4e6cca..3c617e6 100644\n--- a/gravy.txt\n+++ b/gravy.txt\n@@ -5,4 +7,4 @@ pot, put in the same ingredients as for the shin soup, with the same\n quantity of water, and follow the process directed for that. Strain the\n soup through a sieve, and serve it up clear, with nothing more than\n toasted bread in it; two table-spoonsful of mushroom catsup will add a\n-fine flavour to the soup.\n+fine flavour to the soup!\n", buf.ptr);
+
+       git_buf_dispose(&buf);
+       git_patch_free(patch);
+       git_diff_free(diff);
+}
diff --git a/tests/email/create.c b/tests/email/create.c
new file mode 100644 (file)
index 0000000..ccf79c2
--- /dev/null
@@ -0,0 +1,363 @@
+#include "clar.h"
+#include "clar_libgit2.h"
+
+#include "buffer.h"
+#include "diff_generate.h"
+
+static git_repository *repo;
+
+void test_email_create__initialize(void)
+{
+       repo = cl_git_sandbox_init("diff_format_email");
+}
+
+void test_email_create__cleanup(void)
+{
+       cl_git_sandbox_cleanup();
+}
+
+static void email_for_commit(
+       git_buf *out,
+       const char *commit_id,
+       git_email_create_options *opts)
+{
+       git_oid oid;
+       git_commit *commit = NULL;
+       git_diff *diff = NULL;
+
+       git_oid_fromstr(&oid, commit_id);
+
+       cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+
+       cl_git_pass(git_email_create_from_commit(out, commit, opts));
+
+       git_diff_free(diff);
+       git_commit_free(commit);
+}
+
+static void assert_email_match(
+       const char *expected,
+       const char *commit_id,
+       git_email_create_options *opts)
+{
+       git_buf buf = GIT_BUF_INIT;
+
+       email_for_commit(&buf, commit_id, opts);
+       cl_assert_equal_s(expected, git_buf_cstr(&buf));
+
+       git_buf_dispose(&buf);
+}
+
+static void assert_subject_match(
+       const char *expected,
+       const char *commit_id,
+       git_email_create_options *opts)
+{
+       git_buf buf = GIT_BUF_INIT;
+       const char *loc;
+
+       email_for_commit(&buf, commit_id, opts);
+
+       cl_assert((loc = strstr(buf.ptr, "\nSubject: ")) != NULL);
+       git_buf_consume(&buf, (loc + 10));
+       git_buf_truncate_at_char(&buf, '\n');
+
+       cl_assert_equal_s(expected, git_buf_cstr(&buf));
+
+       git_buf_dispose(&buf);
+}
+
+void test_email_create__commit(void)
+{
+       const char *expected =
+       "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \
+       "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+       "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \
+       "Subject: [PATCH] Modify some content\n" \
+       "\n" \
+       "---\n" \
+       " file1.txt | 8 +++++---\n" \
+       " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \
+       "\n" \
+       "diff --git a/file1.txt b/file1.txt\n" \
+       "index 94aaae8..af8f41d 100644\n" \
+       "--- a/file1.txt\n" \
+       "+++ b/file1.txt\n" \
+       "@@ -1,15 +1,17 @@\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       "+_file1.txt_\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       "+\n" \
+       "+\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "+_file1.txt_\n" \
+       "+_file1.txt_\n" \
+       " file1.txt\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       assert_email_match(
+               expected, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", NULL);
+}
+
+void test_email_create__rename(void)
+{
+       const char *expected =
+       "From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \
+       "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+       "Date: Wed, 9 Apr 2014 21:15:56 +0200\n" \
+       "Subject: [PATCH] Renamed file1.txt -> file1.txt.renamed\n" \
+       "\n" \
+       "---\n" \
+       " file1.txt => file1.txt.renamed | 4 ++--\n" \
+       " 1 file changed, 2 insertions(+), 2 deletions(-)\n" \
+       "\n" \
+       "diff --git a/file1.txt b/file1.txt.renamed\n" \
+       "similarity index 86%\n" \
+       "rename from file1.txt\n" \
+       "rename to file1.txt.renamed\n" \
+       "index af8f41d..a97157a 100644\n" \
+       "--- a/file1.txt\n" \
+       "+++ b/file1.txt.renamed\n" \
+       "@@ -3,13 +3,13 @@ file1.txt\n" \
+       " _file1.txt_\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       "-file1.txt\n" \
+       "+file1.txt_renamed\n" \
+       " file1.txt\n" \
+       " \n" \
+       " \n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       "-file1.txt\n" \
+       "+file1.txt_renamed\n" \
+       " file1.txt\n" \
+       " file1.txt\n" \
+       " _file1.txt_\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       assert_email_match(expected, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d", NULL);
+}
+
+void test_email_create__rename_as_add_delete(void)
+{
+       const char *expected =
+       "From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \
+       "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+       "Date: Wed, 9 Apr 2014 21:15:56 +0200\n" \
+       "Subject: [PATCH] Renamed file1.txt -> file1.txt.renamed\n" \
+       "\n" \
+       "---\n" \
+       " file1.txt         | 17 -----------------\n" \
+       " file1.txt.renamed | 17 +++++++++++++++++\n" \
+       " 2 files changed, 17 insertions(+), 17 deletions(-)\n" \
+       " delete mode 100644 file1.txt\n" \
+       " create mode 100644 file1.txt.renamed\n" \
+       "\n" \
+       "diff --git a/file1.txt b/file1.txt\n" \
+       "deleted file mode 100644\n" \
+       "index af8f41d..0000000\n" \
+       "--- a/file1.txt\n" \
+       "+++ /dev/null\n" \
+       "@@ -1,17 +0,0 @@\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-_file1.txt_\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-\n" \
+       "-\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-file1.txt\n" \
+       "-_file1.txt_\n" \
+       "-_file1.txt_\n" \
+       "-file1.txt\n" \
+       "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \
+       "new file mode 100644\n" \
+       "index 0000000..a97157a\n" \
+       "--- /dev/null\n" \
+       "+++ b/file1.txt.renamed\n" \
+       "@@ -0,0 +1,17 @@\n" \
+       "+file1.txt\n" \
+       "+file1.txt\n" \
+       "+_file1.txt_\n" \
+       "+file1.txt\n" \
+       "+file1.txt\n" \
+       "+file1.txt_renamed\n" \
+       "+file1.txt\n" \
+       "+\n" \
+       "+\n" \
+       "+file1.txt\n" \
+       "+file1.txt\n" \
+       "+file1.txt_renamed\n" \
+       "+file1.txt\n" \
+       "+file1.txt\n" \
+       "+_file1.txt_\n" \
+       "+_file1.txt_\n" \
+       "+file1.txt\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+       opts.flags |= GIT_EMAIL_CREATE_NO_RENAMES;
+
+       assert_email_match(expected, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d", &opts);
+}
+
+void test_email_create__binary(void)
+{
+       const char *expected =
+       "From 8d7523f6fcb2404257889abe0d96f093d9f524f9 Mon Sep 17 00:00:00 2001\n" \
+       "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+       "Date: Sun, 13 Apr 2014 18:10:18 +0200\n" \
+       "Subject: [PATCH] Modified binary file\n" \
+       "\n" \
+       "---\n" \
+       " binary.bin | Bin 3 -> 5 bytes\n" \
+       " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \
+       "\n" \
+       "diff --git a/binary.bin b/binary.bin\n" \
+       "index bd474b2519cc15eab801ff851cc7d50f0dee49a1..9ac35ff15cd8864aeafd889e4826a3150f0b06c4 100644\n" \
+       "GIT binary patch\n" \
+       "literal 5\n" \
+       "Mc${NkU}WL~000&M4gdfE\n" \
+       "\n" \
+       "literal 3\n" \
+       "Kc${Nk-~s>u4FC%O\n" \
+       "\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       assert_email_match(expected, "8d7523f6fcb2404257889abe0d96f093d9f524f9", NULL);
+}
+
+void test_email_create__binary_not_included(void)
+{
+       const char *expected =
+       "From 8d7523f6fcb2404257889abe0d96f093d9f524f9 Mon Sep 17 00:00:00 2001\n" \
+       "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+       "Date: Sun, 13 Apr 2014 18:10:18 +0200\n" \
+       "Subject: [PATCH] Modified binary file\n" \
+       "\n" \
+       "---\n" \
+       " binary.bin | Bin 3 -> 5 bytes\n" \
+       " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \
+       "\n" \
+       "diff --git a/binary.bin b/binary.bin\n" \
+       "index bd474b2..9ac35ff 100644\n" \
+       "Binary files a/binary.bin and b/binary.bin differ\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+       opts.diff_opts.flags &= ~GIT_DIFF_SHOW_BINARY;
+
+       assert_email_match(expected, "8d7523f6fcb2404257889abe0d96f093d9f524f9", &opts);
+}
+
+void test_email_create__custom_summary_and_body(void)
+{
+       const char *expected = "From 627e7e12d87e07a83fad5b6bfa25e86ead4a5270 Mon Sep 17 00:00:00 2001\n" \
+       "From: Patrick Steinhardt <ps@pks.im>\n" \
+       "Date: Tue, 24 Nov 2015 13:34:39 +0100\n" \
+       "Subject: [PPPPPATCH 2/4] This is a subject\n" \
+       "\n" \
+       "Modify content of file3.txt by appending a new line. Make this\n" \
+       "commit message somewhat longer to test behavior with newlines\n" \
+       "embedded in the message body.\n" \
+       "\n" \
+       "Also test if new paragraphs are included correctly.\n" \
+       "---\n" \
+       " file3.txt | 1 +\n" \
+       " 1 file changed, 1 insertion(+)\n" \
+       "\n" \
+       "diff --git a/file3.txt b/file3.txt\n" \
+       "index 9a2d780..7309653 100644\n" \
+       "--- a/file3.txt\n" \
+       "+++ b/file3.txt\n" \
+       "@@ -3,3 +3,4 @@ file3!\n" \
+       " file3\n" \
+       " file3\n" \
+       " file3\n" \
+       "+file3\n" \
+       "--\n" \
+       "libgit2 " LIBGIT2_VERSION "\n" \
+       "\n";
+
+       const char *summary = "This is a subject\nwith\nnewlines";
+       const char *body = "Modify content of file3.txt by appending a new line. Make this\n" \
+       "commit message somewhat longer to test behavior with newlines\n" \
+       "embedded in the message body.\n" \
+       "\n" \
+       "Also test if new paragraphs are included correctly.";
+
+       git_oid oid;
+       git_commit *commit = NULL;
+       git_diff *diff = NULL;
+       git_buf buf = GIT_BUF_INIT;
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+
+       opts.subject_prefix = "PPPPPATCH";
+
+       git_oid_fromstr(&oid, "627e7e12d87e07a83fad5b6bfa25e86ead4a5270");
+       cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+       cl_git_pass(git_diff__commit(&diff, repo, commit, NULL));
+       cl_git_pass(git_email_create_from_diff(&buf, diff, 2, 4, &oid, summary, body, git_commit_author(commit), &opts));
+
+       cl_assert_equal_s(expected, git_buf_cstr(&buf));
+
+       git_diff_free(diff);
+       git_commit_free(commit);
+       git_buf_dispose(&buf);
+}
+
+void test_email_create__commit_subjects(void)
+{
+       git_email_create_options opts = GIT_EMAIL_CREATE_OPTIONS_INIT;
+
+       assert_subject_match("[PATCH] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.reroll_number = 42;
+       assert_subject_match("[PATCH v42] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.flags |= GIT_EMAIL_CREATE_ALWAYS_NUMBER;
+       assert_subject_match("[PATCH v42 1/1] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.start_number = 9;
+       assert_subject_match("[PATCH v42 9/9] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.subject_prefix = "";
+       assert_subject_match("[v42 9/9] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.reroll_number = 0;
+       assert_subject_match("[9/9] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.start_number = 0;
+       assert_subject_match("[1/1] Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+
+       opts.flags = GIT_EMAIL_CREATE_OMIT_NUMBERS;
+       assert_subject_match("Modify some content", "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts);
+}
index 6cea6d166c9f9bd20870bf536b0c516df5c928f0..6881af40a0099a574ba1cb705500030545d9a03b 100644 (file)
@@ -82,7 +82,7 @@ void test_fetchhead_nonetwork__write(void)
        int equals = 0;
        size_t i;
 
-       git_vector_init(&fetchhead_vector, 6, NULL);
+       cl_git_pass(git_vector_init(&fetchhead_vector, 6, NULL));
 
        cl_set_cleanup(&cleanup_repository, "./test1");
        cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
@@ -319,6 +319,16 @@ static int assert_master_for_merge(const char *ref, const char *url, const git_o
        return 0;
 }
 
+static int assert_none_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data)
+{
+       GIT_UNUSED(ref);
+       GIT_UNUSED(url);
+       GIT_UNUSED(id);
+       GIT_UNUSED(data);
+
+       return is_merge ? -1 : 0;
+}
+
 void test_fetchhead_nonetwork__unborn_with_upstream(void)
 {
        git_repository *repo;
@@ -366,6 +376,25 @@ void test_fetchhead_nonetwork__fetch_into_repo_with_symrefs(void)
        cl_git_sandbox_cleanup();
 }
 
+void test_fetchhead_nonetwork__fetch_into_repo_with_invalid_head(void)
+{
+       git_remote *remote;
+       char *strings[] = { "refs/heads/*:refs/remotes/origin/*" };
+       git_strarray refspecs = { strings, 1 };
+
+       cl_set_cleanup(&cleanup_repository, "./test1");
+       cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
+
+       /* HEAD pointing to nonexistent branch */
+       cl_git_rewritefile("./test1/.git/HEAD", "ref: refs/heads/\n");
+
+       cl_git_pass(git_remote_create_anonymous(&remote, g_repo, cl_fixture("testrepo.git")));
+       cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, NULL));
+       cl_git_pass(git_repository_fetchhead_foreach(g_repo, assert_none_for_merge, NULL));
+
+       git_remote_free(remote);
+}
+
 void test_fetchhead_nonetwork__quote_in_branch_name(void)
 {
        cl_set_cleanup(&cleanup_repository, "./test1");
index 430931ee8db15861e4d3a975bca3f267d00b0434..8402638cefc339e9cabde8db06fe15028d4508f9 100644 (file)
@@ -10,7 +10,7 @@ void test_filter_bare__initialize(void)
        cl_git_pass(git_repository_open(&g_repo, "crlf.git"));
 
        filter_opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
-       filter_opts.flags |= GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD;
+       filter_opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD;
 }
 
 void test_filter_bare__cleanup(void)
@@ -132,3 +132,57 @@ void test_filter_bare__sanitizes(void)
        git_blob_free(blob);
 }
 
+void test_filter_bare__from_specific_commit_one(void)
+{
+       git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+       git_blob *blob;
+       git_buf buf = { 0 };
+
+       opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
+       opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
+       cl_git_pass(git_oid_fromstr(&opts.attr_commit_id, "b8986fec0f7bde90f78ac72706e782d82f24f2f0"));
+
+       cl_git_pass(git_revparse_single(
+               (git_object **)&blob, g_repo, "055c872")); /* ident */
+
+       cl_assert_equal_s("$Id$\n", git_blob_rawcontent(blob));
+
+       cl_git_pass(git_blob_filter(&buf, blob, "ident.bin", &opts));
+       cl_assert_equal_s("$Id$\n", buf.ptr);
+
+       cl_git_pass(git_blob_filter(&buf, blob, "ident.identlf", &opts));
+       cl_assert_equal_s("$Id: 055c8729cdcc372500a08db659c045e16c4409fb $\n", buf.ptr);
+
+       git_buf_dispose(&buf);
+       git_blob_free(blob);
+}
+
+void test_filter_bare__from_specific_commit_with_no_attributes_file(void)
+{
+       git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+       git_blob *blob;
+       git_buf buf = { 0 };
+
+       opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
+       opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
+       cl_git_pass(git_oid_fromstr(&opts.attr_commit_id, "5afb6a14a864e30787857dd92af837e8cdd2cb1b"));
+
+       cl_git_pass(git_revparse_single(
+               (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+       cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+       cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &opts));
+       cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+       /* we never convert CRLF -> LF on platforms that have LF */
+       cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &opts));
+       cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+       /* we never convert CRLF -> LF on platforms that have LF */
+       cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &opts));
+       cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+       git_buf_dispose(&buf);
+       git_blob_free(blob);
+}
index a266005d4de325fe42df74afe57b204e151dc7bb..bc9c7f289389d0e23258fcf7950b0432670632b5 100644 (file)
@@ -23,7 +23,9 @@ void test_filter_crlf__to_worktree(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = { 0 }, out = { 0 };
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_new(
                &fl, g_repo, GIT_FILTER_TO_WORKTREE, 0));
@@ -33,10 +35,10 @@ void test_filter_crlf__to_worktree(void)
 
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
-       in.ptr = "Some text\nRight here\n";
-       in.size = strlen(in.ptr);
+       in = "Some text\nRight here\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
 
        cl_assert_equal_s("Some text\r\nRight here\r\n", out.ptr);
 
@@ -48,7 +50,9 @@ void test_filter_crlf__to_odb(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = { 0 }, out = { 0 };
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_new(
                &fl, g_repo, GIT_FILTER_TO_ODB, 0));
@@ -58,10 +62,10 @@ void test_filter_crlf__to_odb(void)
 
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
-       in.ptr = "Some text\r\nRight here\r\n";
-       in.size = strlen(in.ptr);
+       in = "Some text\r\nRight here\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
 
        cl_assert_equal_s("Some text\nRight here\n", out.ptr);
 
@@ -73,7 +77,9 @@ void test_filter_crlf__with_safecrlf(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = {0}, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_repo_set_bool(g_repo, "core.safecrlf", true);
 
@@ -86,31 +92,31 @@ void test_filter_crlf__with_safecrlf(void)
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
        /* Normalized \r\n succeeds with safecrlf */
-       in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\r\nCRLF\r\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
 
        /* Mix of line endings fails with safecrlf */
-       in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_fail(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_i(git_error_last()->klass, GIT_ERROR_FILTER);
 
        /* Normalized \n fails for autocrlf=true when safecrlf=true */
-       in.ptr = "Normal\nLF\nonly\nline-endings.\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\nLF\nonly\nline-endings.\n";
+       in_len = strlen(in);
 
-       cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_fail(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_i(git_error_last()->klass, GIT_ERROR_FILTER);
 
        /* String with \r but without \r\n does not fail with safecrlf */
-       in.ptr = "Normal\nCR only\rand some more\nline-endings.\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\nCR only\rand some more\nline-endings.\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nCR only\rand some more\nline-endings.\n", out.ptr);
 
        git_filter_list_free(fl);
@@ -121,7 +127,9 @@ void test_filter_crlf__with_safecrlf_and_unsafe_allowed(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = {0}, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_repo_set_bool(g_repo, "core.safecrlf", true);
 
@@ -134,25 +142,25 @@ void test_filter_crlf__with_safecrlf_and_unsafe_allowed(void)
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
        /* Normalized \r\n succeeds with safecrlf */
-       in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\r\nCRLF\r\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
 
        /* Mix of line endings fails with safecrlf, but allowed to pass */
-       in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        /* TODO: check for warning */
        cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr);
 
        /* Normalized \n fails with safecrlf, but allowed to pass */
-       in.ptr = "Normal\nLF\nonly\nline-endings.\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\nLF\nonly\nline-endings.\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        /* TODO: check for warning */
        cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr);
 
@@ -164,7 +172,9 @@ void test_filter_crlf__no_safecrlf(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = {0}, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_new(
                &fl, g_repo, GIT_FILTER_TO_ODB, 0));
@@ -175,24 +185,24 @@ void test_filter_crlf__no_safecrlf(void)
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
        /* Normalized \r\n succeeds with safecrlf */
-       in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\r\nCRLF\r\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
 
        /* Mix of line endings fails with safecrlf */
-       in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr);
 
        /* Normalized \n fails with safecrlf */
-       in.ptr = "Normal\nLF\nonly\nline-endings.\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\nLF\nonly\nline-endings.\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr);
 
        git_filter_list_free(fl);
@@ -203,7 +213,9 @@ void test_filter_crlf__safecrlf_warn(void)
 {
        git_filter_list *fl;
        git_filter *crlf;
-       git_buf in = {0}, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_repo_set_string(g_repo, "core.safecrlf", "warn");
 
@@ -216,26 +228,26 @@ void test_filter_crlf__safecrlf_warn(void)
        cl_git_pass(git_filter_list_push(fl, crlf, NULL));
 
        /* Normalized \r\n succeeds with safecrlf=warn */
-       in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\r\nCRLF\r\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
 
        /* Mix of line endings succeeds with safecrlf=warn */
-       in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
-       in.size = strlen(in.ptr);
+       in = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
        /* TODO: check for warning */
        cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr);
 
        /* Normalized \n is reversible, so does not fail with safecrlf=warn */
-       in.ptr = "Normal\nLF\nonly\nline-endings.\n";
-       in.size = strlen(in.ptr);
+       in = "Normal\nLF\nonly\nline-endings.\n";
+       in_len = strlen(in);
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
-       cl_assert_equal_s(in.ptr, out.ptr);
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
+       cl_assert_equal_s(in, out.ptr);
 
        git_filter_list_free(fl);
        git_buf_dispose(&out);
index fe2025fc2c911558602bc05d44d3cbb3104ceca6..57cef33ce7db3151f0f93e09817794fb0a2a0c81 100644 (file)
@@ -2,7 +2,6 @@
 #include "posix.h"
 #include "blob.h"
 #include "filter.h"
-#include "buf_text.h"
 #include "git2/sys/filter.h"
 #include "git2/sys/repository.h"
 #include "custom_helpers.h"
@@ -95,13 +94,17 @@ static void register_custom_filters(void)
 void test_filter_custom__to_odb(void)
 {
        git_filter_list *fl;
-       git_buf out = { 0 };
-       git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data));
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_load(
                &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_ODB, 0));
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       in = workdir_data;
+       in_len = strlen(workdir_data);
+
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
 
        cl_assert_equal_i(BITFLIPPED_AND_REVERSED_DATA_LEN, out.size);
 
@@ -115,14 +118,17 @@ void test_filter_custom__to_odb(void)
 void test_filter_custom__to_workdir(void)
 {
        git_filter_list *fl;
-       git_buf out = { 0 };
-       git_buf in = GIT_BUF_INIT_CONST(
-               bitflipped_and_reversed_data, BITFLIPPED_AND_REVERSED_DATA_LEN);
+       git_buf out = GIT_BUF_INIT;
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_load(
                &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE, 0));
 
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       in = (char *)bitflipped_and_reversed_data;
+       in_len = BITFLIPPED_AND_REVERSED_DATA_LEN;
+
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, in, in_len));
 
        cl_assert_equal_i(strlen(workdir_data), out.size);
 
@@ -246,12 +252,16 @@ void test_filter_custom__erroneous_filter_fails(void)
 {
        git_filter_list *filters;
        git_buf out = GIT_BUF_INIT;
-       git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data));
+       const char *in;
+       size_t in_len;
 
        cl_git_pass(git_filter_list_load(
                &filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0));
 
-       cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in));
+       in = workdir_data;
+       in_len = strlen(workdir_data);
+
+       cl_git_fail(git_filter_list_apply_to_buffer(&out, filters, in, in_len));
 
        git_filter_list_free(filters);
        git_buf_dispose(&out);
index d7f2afe7af913dc6d520760693a67284f7de649a..ee3b6353b322c265a7a5cb5e5383e82c00370e34 100644 (file)
@@ -1,7 +1,6 @@
 #include "clar_libgit2.h"
 #include "posix.h"
 #include "filter.h"
-#include "buf_text.h"
 #include "git2/sys/filter.h"
 
 #define VERY_SECURE_ENCRYPTION(b) ((b) ^ 0xff)
@@ -38,6 +37,17 @@ int bitflip_filter_apply(
        return 0;
 }
 
+static int bitflip_filter_stream(
+       git_writestream **out,
+       git_filter *self,
+       void **payload,
+       const git_filter_source *src,
+       git_writestream *next)
+{
+       return git_filter_buffered_stream_new(out,
+               self, bitflip_filter_apply, NULL, payload, src, next);
+}
+
 static void bitflip_filter_free(git_filter *f)
 {
        git__free(f);
@@ -51,7 +61,7 @@ git_filter *create_bitflip_filter(void)
        filter->version = GIT_FILTER_VERSION;
        filter->attributes = "+bitflip";
        filter->shutdown = bitflip_filter_free;
-       filter->apply = bitflip_filter_apply;
+       filter->stream = bitflip_filter_stream;
 
        return filter;
 }
@@ -89,6 +99,17 @@ int reverse_filter_apply(
        return 0;
 }
 
+static int reverse_filter_stream(
+       git_writestream **out,
+       git_filter *self,
+       void **payload,
+       const git_filter_source *src,
+       git_writestream *next)
+{
+       return git_filter_buffered_stream_new(out,
+               self, reverse_filter_apply, NULL, payload, src, next);
+}
+
 static void reverse_filter_free(git_filter *f)
 {
        git__free(f);
@@ -102,7 +123,7 @@ git_filter *create_reverse_filter(const char *attrs)
        filter->version = GIT_FILTER_VERSION;
        filter->attributes = attrs;
        filter->shutdown = reverse_filter_free;
-       filter->apply = reverse_filter_apply;
+       filter->stream = reverse_filter_stream;
 
        return filter;
 }
index 226092c3f32343e504cdd18a844f6e1b6455b03a..b6a4c3ca1fae68f9b50c3a8b14ed0b9aaf29846f 100644 (file)
@@ -2,7 +2,6 @@
 #include "posix.h"
 #include "blob.h"
 #include "filter.h"
-#include "buf_text.h"
 #include "git2/sys/filter.h"
 #include "git2/sys/repository.h"
 
index 3c25ea266138386ff5077981be4b656d9c6d83be..0c9c13b1e4c6b338f95331c38a0f4e4d557f1433 100644 (file)
@@ -2,7 +2,6 @@
 #include "posix.h"
 #include "blob.h"
 #include "filter.h"
-#include "buf_text.h"
 #include "git2/sys/filter.h"
 #include "git2/sys/repository.h"
 #include "custom_helpers.h"
@@ -94,6 +93,17 @@ static int wildcard_filter_apply(
        return GIT_PASSTHROUGH;
 }
 
+static int wildcard_filter_stream(
+       git_writestream **out,
+       git_filter *self,
+       void **payload,
+       const git_filter_source *src,
+       git_writestream *next)
+{
+       return git_filter_buffered_stream_new(out,
+               self, wildcard_filter_apply, NULL, payload, src, next);
+}
+
 static void wildcard_filter_cleanup(git_filter *self, void *payload)
 {
        GIT_UNUSED(self);
@@ -113,7 +123,7 @@ static git_filter *create_wildcard_filter(void)
        filter->version = GIT_FILTER_VERSION;
        filter->attributes = "filter=*";
        filter->check = wildcard_filter_check;
-       filter->apply = wildcard_filter_apply;
+       filter->stream = wildcard_filter_stream;
        filter->cleanup = wildcard_filter_cleanup;
        filter->shutdown = wildcard_filter_free;
 
@@ -123,13 +133,12 @@ static git_filter *create_wildcard_filter(void)
 void test_filter_wildcard__reverse(void)
 {
        git_filter_list *fl;
-       git_buf in = GIT_BUF_INIT, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
 
        cl_git_pass(git_filter_list_load(
                &fl, g_repo, NULL, "hero-reverse-foo", GIT_FILTER_TO_ODB, 0));
 
-       cl_git_pass(git_buf_put(&in, (char *)input, DATA_LEN));
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, (char *)input, DATA_LEN));
 
        cl_assert_equal_i(DATA_LEN, out.size);
 
@@ -138,19 +147,17 @@ void test_filter_wildcard__reverse(void)
 
        git_filter_list_free(fl);
        git_buf_dispose(&out);
-       git_buf_dispose(&in);
 }
 
 void test_filter_wildcard__flip(void)
 {
        git_filter_list *fl;
-       git_buf in = GIT_BUF_INIT, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
 
        cl_git_pass(git_filter_list_load(
                &fl, g_repo, NULL, "hero-flip-foo", GIT_FILTER_TO_ODB, 0));
 
-       cl_git_pass(git_buf_put(&in, (char *)input, DATA_LEN));
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, (char *)input, DATA_LEN));
 
        cl_assert_equal_i(DATA_LEN, out.size);
 
@@ -159,19 +166,17 @@ void test_filter_wildcard__flip(void)
 
        git_filter_list_free(fl);
        git_buf_dispose(&out);
-       git_buf_dispose(&in);
 }
 
 void test_filter_wildcard__none(void)
 {
        git_filter_list *fl;
-       git_buf in = GIT_BUF_INIT, out = GIT_BUF_INIT;
+       git_buf out = GIT_BUF_INIT;
 
        cl_git_pass(git_filter_list_load(
                &fl, g_repo, NULL, "none-foo", GIT_FILTER_TO_ODB, 0));
 
-       cl_git_pass(git_buf_put(&in, (char *)input, DATA_LEN));
-       cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
+       cl_git_pass(git_filter_list_apply_to_buffer(&out, fl, (char *)input, DATA_LEN));
 
        cl_assert_equal_i(DATA_LEN, out.size);
 
@@ -180,5 +185,4 @@ void test_filter_wildcard__none(void)
 
        git_filter_list_free(fl);
        git_buf_dispose(&out);
-       git_buf_dispose(&in);
 }
diff --git a/tests/graph/commit_graph.c b/tests/graph/commit_graph.c
new file mode 100644 (file)
index 0000000..5926dca
--- /dev/null
@@ -0,0 +1,125 @@
+#include "clar_libgit2.h"
+
+#include <git2.h>
+#include <git2/sys/commit_graph.h>
+
+#include "commit_graph.h"
+#include "futils.h"
+
+void test_graph_commit_graph__parse(void)
+{
+       git_repository *repo;
+       struct git_commit_graph_file *file;
+       struct git_commit_graph_entry e, parent;
+       git_oid id;
+       git_buf commit_graph_path = GIT_BUF_INIT;
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+       cl_git_pass(git_buf_joinpath(&commit_graph_path, git_repository_path(repo), "objects/info/commit-graph"));
+       cl_git_pass(git_commit_graph_file_open(&file, git_buf_cstr(&commit_graph_path)));
+       cl_assert_equal_i(git_commit_graph_file_needs_refresh(file, git_buf_cstr(&commit_graph_path)), 0);
+
+       cl_git_pass(git_oid_fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5"));
+       cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_HEXSZ));
+       cl_assert_equal_oid(&e.sha1, &id);
+       cl_git_pass(git_oid_fromstr(&id, "418382dff1ffb8bdfba833f4d8bbcde58b1e7f47"));
+       cl_assert_equal_oid(&e.tree_oid, &id);
+       cl_assert_equal_i(e.generation, 1);
+       cl_assert_equal_i(e.commit_time, UINT64_C(1273610423));
+       cl_assert_equal_i(e.parent_count, 0);
+
+       cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
+       cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_HEXSZ));
+       cl_assert_equal_oid(&e.sha1, &id);
+       cl_assert_equal_i(e.generation, 5);
+       cl_assert_equal_i(e.commit_time, UINT64_C(1274813907));
+       cl_assert_equal_i(e.parent_count, 2);
+
+       cl_git_pass(git_oid_fromstr(&id, "9fd738e8f7967c078dceed8190330fc8648ee56a"));
+       cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 0));
+       cl_assert_equal_oid(&parent.sha1, &id);
+       cl_assert_equal_i(parent.generation, 4);
+
+       cl_git_pass(git_oid_fromstr(&id, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
+       cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 1));
+       cl_assert_equal_oid(&parent.sha1, &id);
+       cl_assert_equal_i(parent.generation, 3);
+
+       git_commit_graph_file_free(file);
+       git_repository_free(repo);
+       git_buf_dispose(&commit_graph_path);
+}
+
+void test_graph_commit_graph__parse_octopus_merge(void)
+{
+       git_repository *repo;
+       struct git_commit_graph_file *file;
+       struct git_commit_graph_entry e, parent;
+       git_oid id;
+       git_buf commit_graph_path = GIT_BUF_INIT;
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("merge-recursive/.gitted")));
+       cl_git_pass(git_buf_joinpath(&commit_graph_path, git_repository_path(repo), "objects/info/commit-graph"));
+       cl_git_pass(git_commit_graph_file_open(&file, git_buf_cstr(&commit_graph_path)));
+
+       cl_git_pass(git_oid_fromstr(&id, "d71c24b3b113fd1d1909998c5bfe33b86a65ee03"));
+       cl_git_pass(git_commit_graph_entry_find(&e, file, &id, GIT_OID_HEXSZ));
+       cl_assert_equal_oid(&e.sha1, &id);
+       cl_git_pass(git_oid_fromstr(&id, "348f16ffaeb73f319a75cec5b16a0a47d2d5e27c"));
+       cl_assert_equal_oid(&e.tree_oid, &id);
+       cl_assert_equal_i(e.generation, 7);
+       cl_assert_equal_i(e.commit_time, UINT64_C(1447083009));
+       cl_assert_equal_i(e.parent_count, 3);
+
+       cl_git_pass(git_oid_fromstr(&id, "ad2ace9e15f66b3d1138922e6ffdc3ea3f967fa6"));
+       cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 0));
+       cl_assert_equal_oid(&parent.sha1, &id);
+       cl_assert_equal_i(parent.generation, 6);
+
+       cl_git_pass(git_oid_fromstr(&id, "483065df53c0f4a02cdc6b2910b05d388fc17ffb"));
+       cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 1));
+       cl_assert_equal_oid(&parent.sha1, &id);
+       cl_assert_equal_i(parent.generation, 2);
+
+       cl_git_pass(git_oid_fromstr(&id, "815b5a1c80ca749d705c7aa0cb294a00cbedd340"));
+       cl_git_pass(git_commit_graph_entry_parent(&parent, file, &e, 2));
+       cl_assert_equal_oid(&parent.sha1, &id);
+       cl_assert_equal_i(parent.generation, 6);
+
+       git_commit_graph_file_free(file);
+       git_repository_free(repo);
+       git_buf_dispose(&commit_graph_path);
+}
+
+void test_graph_commit_graph__writer(void)
+{
+       git_repository *repo;
+       git_commit_graph_writer *w = NULL;
+       git_revwalk *walk;
+       git_commit_graph_writer_options opts = GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT;
+       git_buf cgraph = GIT_BUF_INIT, expected_cgraph = GIT_BUF_INIT, path = GIT_BUF_INIT;
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+
+       cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/info"));
+       cl_git_pass(git_commit_graph_writer_new(&w, git_buf_cstr(&path)));
+
+       /* This is equivalent to `git commit-graph write --reachable`. */
+       cl_git_pass(git_revwalk_new(&walk, repo));
+       cl_git_pass(git_revwalk_push_glob(walk, "refs/*"));
+       cl_git_pass(git_commit_graph_writer_add_revwalk(w, walk));
+       git_revwalk_free(walk);
+
+       cl_git_pass(git_commit_graph_writer_dump(&cgraph, w, &opts));
+       cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/info/commit-graph"));
+       cl_git_pass(git_futils_readbuffer(&expected_cgraph, git_buf_cstr(&path)));
+
+       cl_assert_equal_i(git_buf_len(&cgraph), git_buf_len(&expected_cgraph));
+       cl_assert_equal_i(memcmp(git_buf_cstr(&cgraph), git_buf_cstr(&expected_cgraph), git_buf_len(&cgraph)), 0);
+
+       git_buf_dispose(&cgraph);
+       git_buf_dispose(&expected_cgraph);
+       git_buf_dispose(&path);
+       git_commit_graph_writer_free(w);
+       git_repository_free(repo);
+}
diff --git a/tests/graph/reachable_from_any.c b/tests/graph/reachable_from_any.c
new file mode 100644 (file)
index 0000000..5c84164
--- /dev/null
@@ -0,0 +1,236 @@
+#include "clar_libgit2.h"
+
+#include <git2.h>
+
+#include "commit_graph.h"
+#include "bitvec.h"
+#include "vector.h"
+
+static git_repository *repo;
+
+#define TEST_REPO_PATH "merge-recursive"
+
+void test_graph_reachable_from_any__initialize(void)
+{
+       git_oid oid;
+       git_commit *commit;
+
+       repo = cl_git_sandbox_init(TEST_REPO_PATH);
+
+       git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707");
+       cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+       cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL));
+       git_commit_free(commit);
+}
+
+void test_graph_reachable_from_any__cleanup(void)
+{
+       cl_git_sandbox_cleanup();
+}
+
+void test_graph_reachable_from_any__returns_correct_result(void)
+{
+       git_object *branchA1, *branchA2, *branchB1, *branchB2, *branchC1, *branchC2, *branchH1,
+                       *branchH2;
+       git_oid descendants[7];
+
+       cl_git_pass(git_revparse_single(&branchA1, repo, "branchA-1"));
+       cl_git_pass(git_revparse_single(&branchA2, repo, "branchA-2"));
+       cl_git_pass(git_revparse_single(&branchB1, repo, "branchB-1"));
+       cl_git_pass(git_revparse_single(&branchB2, repo, "branchB-2"));
+       cl_git_pass(git_revparse_single(&branchC1, repo, "branchC-1"));
+       cl_git_pass(git_revparse_single(&branchC2, repo, "branchC-2"));
+       cl_git_pass(git_revparse_single(&branchH1, repo, "branchH-1"));
+       cl_git_pass(git_revparse_single(&branchH2, repo, "branchH-2"));
+
+       cl_assert_equal_i(
+                       git_graph_reachable_from_any(
+                                       repo, git_object_id(branchH1), git_object_id(branchA1), 1),
+                       0);
+       cl_assert_equal_i(
+                       git_graph_reachable_from_any(
+                                       repo, git_object_id(branchH1), git_object_id(branchA2), 1),
+                       0);
+
+       cl_git_pass(git_oid_cpy(&descendants[0], git_object_id(branchA1)));
+       cl_git_pass(git_oid_cpy(&descendants[1], git_object_id(branchA2)));
+       cl_git_pass(git_oid_cpy(&descendants[2], git_object_id(branchB1)));
+       cl_git_pass(git_oid_cpy(&descendants[3], git_object_id(branchB2)));
+       cl_git_pass(git_oid_cpy(&descendants[4], git_object_id(branchC1)));
+       cl_git_pass(git_oid_cpy(&descendants[5], git_object_id(branchC2)));
+       cl_git_pass(git_oid_cpy(&descendants[6], git_object_id(branchH2)));
+       cl_assert_equal_i(
+                       git_graph_reachable_from_any(repo, git_object_id(branchH2), descendants, 6),
+                       0);
+       cl_assert_equal_i(
+                       git_graph_reachable_from_any(repo, git_object_id(branchH2), descendants, 7),
+                       1);
+
+       git_object_free(branchA1);
+       git_object_free(branchA2);
+       git_object_free(branchB1);
+       git_object_free(branchB2);
+       git_object_free(branchC1);
+       git_object_free(branchC2);
+       git_object_free(branchH1);
+       git_object_free(branchH2);
+}
+
+struct exhaustive_state {
+       git_odb *db;
+       git_vector commits;
+};
+
+/** Get all commits from the repository. */
+static int exhaustive_commits(const git_oid *id, void *payload)
+{
+       struct exhaustive_state *mc = (struct exhaustive_state *)payload;
+       size_t header_len;
+       git_object_t header_type;
+       int error = 0;
+
+       error = git_odb_read_header(&header_len, &header_type, mc->db, id);
+       if (error < 0)
+               return error;
+
+       if (header_type == GIT_OBJECT_COMMIT) {
+               git_commit *commit = NULL;
+
+               cl_git_pass(git_commit_lookup(&commit, repo, id));
+               cl_git_pass(git_vector_insert(&mc->commits, commit));
+       }
+
+       return 0;
+}
+
+/** Compare the `git_oid`s of two `git_commit` objects. */
+static int commit_id_cmp(const void *a, const void *b)
+{
+       return git_oid_cmp(
+                       git_commit_id((const git_commit *)a), git_commit_id((const git_commit *)b));
+}
+
+/** Find a `git_commit` whose ID matches the provided `git_oid` key. */
+static int id_commit_id_cmp(const void *key, const void *commit)
+{
+       return git_oid_cmp((const git_oid *)key, git_commit_id((const git_commit *)commit));
+}
+
+void test_graph_reachable_from_any__exhaustive(void)
+{
+       struct exhaustive_state mc = {
+                       .db = NULL,
+                       .commits = GIT_VECTOR_INIT,
+       };
+       size_t child_idx, commit_count;
+       size_t n_descendants;
+       git_commit *child_commit;
+       git_bitvec reachable;
+
+       cl_git_pass(git_repository_odb(&mc.db, repo));
+       cl_git_pass(git_odb_foreach(mc.db, &exhaustive_commits, &mc));
+       git_vector_set_cmp(&mc.commits, commit_id_cmp);
+       git_vector_sort(&mc.commits);
+       cl_git_pass(git_bitvec_init(
+                       &reachable,
+                       git_vector_length(&mc.commits) * git_vector_length(&mc.commits)));
+
+       commit_count = git_vector_length(&mc.commits);
+       git_vector_foreach (&mc.commits, child_idx, child_commit) {
+               unsigned int parent_i;
+
+               /* We treat each commit as being able to reach itself. */
+               git_bitvec_set(&reachable, child_idx * commit_count + child_idx, true);
+
+               for (parent_i = 0; parent_i < git_commit_parentcount(child_commit); ++parent_i) {
+                       size_t parent_idx = -1;
+                       cl_git_pass(git_vector_bsearch2(
+                                       &parent_idx,
+                                       &mc.commits,
+                                       id_commit_id_cmp,
+                                       git_commit_parent_id(child_commit, parent_i)));
+
+                       /* We have established that parent_idx is reachable from child_idx */
+                       git_bitvec_set(&reachable, parent_idx * commit_count + child_idx, true);
+               }
+       }
+
+       /* Floyd-Warshall */
+       {
+               size_t i, j, k;
+               for (k = 0; k < commit_count; ++k) {
+                       for (i = 0; i < commit_count; ++i) {
+                               if (!git_bitvec_get(&reachable, i * commit_count + k))
+                                       continue;
+                               for (j = 0; j < commit_count; ++j) {
+                                       if (!git_bitvec_get(&reachable, k * commit_count + j))
+                                               continue;
+                                       git_bitvec_set(&reachable, i * commit_count + j, true);
+                               }
+                       }
+               }
+       }
+
+       /* Try 1000 subsets of 1 through 10 entries each. */
+       srand(0x223ddc4b);
+       for (n_descendants = 1; n_descendants < 10; ++n_descendants) {
+               size_t test_iteration;
+               git_oid descendants[10];
+
+               for (test_iteration = 0; test_iteration < 1000; ++test_iteration) {
+                       size_t descendant_i;
+                       size_t child_idx, parent_idx;
+                       int expected_reachable = false, actual_reachable;
+                       git_commit *child_commit, *parent_commit;
+
+                       parent_idx = rand() % commit_count;
+                       parent_commit = (git_commit *)git_vector_get(&mc.commits, parent_idx);
+                       for (descendant_i = 0; descendant_i < n_descendants; ++descendant_i) {
+                               child_idx = rand() % commit_count;
+                               child_commit = (git_commit *)git_vector_get(&mc.commits, child_idx);
+                               expected_reachable |= git_bitvec_get(
+                                               &reachable, parent_idx * commit_count + child_idx);
+                               git_oid_cpy(&descendants[descendant_i],
+                                           git_commit_id(child_commit));
+                       }
+
+                       actual_reachable = git_graph_reachable_from_any(
+                                       repo,
+                                       git_commit_id(parent_commit),
+                                       descendants,
+                                       n_descendants);
+                       if (actual_reachable != expected_reachable) {
+                               git_buf error_message_buf = GIT_BUF_INIT;
+                               char parent_oidbuf[9] = {0}, child_oidbuf[9] = {0};
+
+                               cl_git_pass(git_oid_nfmt(
+                                               parent_oidbuf, 8, git_commit_id(parent_commit)));
+                               git_buf_printf(&error_message_buf,
+                                              "git_graph_reachable_from_any(\"%s\", %zu, "
+                                              "{",
+                                              parent_oidbuf,
+                                              n_descendants);
+                               for (descendant_i = 0; descendant_i < n_descendants;
+                                    ++descendant_i) {
+                                       cl_git_pass(
+                                                       git_oid_nfmt(child_oidbuf,
+                                                                    8,
+                                                                    &descendants[descendant_i]));
+                                       git_buf_printf(&error_message_buf, " \"%s\"", child_oidbuf);
+                               }
+                               git_buf_printf(&error_message_buf,
+                                              " }) = %d, expected = %d",
+                                              actual_reachable,
+                                              expected_reachable);
+                               cl_check_(actual_reachable == expected_reachable,
+                                         git_buf_cstr(&error_message_buf));
+                       }
+               }
+       }
+
+       git_vector_foreach (&mc.commits, child_idx, child_commit)
+               git_commit_free(child_commit);
+       git_bitvec_free(&reachable);
+       git_vector_free(&mc.commits);
+       git_odb_free(mc.db);
+}
index 5d53c9df93694fc2925515a1dd4950c6909ad610..d55bdc5dd23cefd0d78889711ab344ce87cfa69a 100644 (file)
@@ -575,3 +575,11 @@ void test_ignore_path__negative_prefix_rule(void)
        assert_is_ignored(true, "ff");
        assert_is_ignored(false, "f");
 }
+
+void test_ignore_path__negative_more_specific(void)
+{
+       cl_git_rewritefile("attr/.gitignore", "*.txt\n!/dir/test.txt\n");
+       assert_is_ignored(true, "test.txt");
+       assert_is_ignored(false, "dir/test.txt");
+       assert_is_ignored(true, "outer/dir/test.txt");
+}
index 188fbe46966e5305e1f5025cba829425251d88ee..83e821bdd8cfac40ec18139d098e5e3a43a80452 100644 (file)
@@ -70,9 +70,9 @@ void test_ignore_status__0(void)
 
        /* confirm that ignore files were cached */
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/exclude"));
        cl_assert(git_attr_cache__is_cached(
-               g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
+               g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitignore"));
 }
 
 
index d1ef31dafe2ba47be75754ba20ddaba1d1404e4a..6f95f6386f4b8150b64bb3543ecb4c3803fea9f4 100644 (file)
@@ -318,11 +318,9 @@ void test_index_addall__files_in_folders(void)
 
 void test_index_addall__hidden_files(void)
 {
+#ifdef GIT_WIN32
        git_index *index;
 
-       GIT_UNUSED(index);
-
-#ifdef GIT_WIN32
        addall_create_test_repo(true);
 
        cl_git_pass(git_repository_index(&index, g_repo));
index 21d3d3ed0b2cc652d3ba4893f421d72bccb16987..b32a0a789e6c75c0517a2a5970567eeae80244b2 100644 (file)
@@ -49,13 +49,10 @@ void test_index_bypath__add_submodule_unregistered(void)
 
 void test_index_bypath__add_hidden(void)
 {
+#ifdef GIT_WIN32
        const git_index_entry *entry;
        bool hidden;
 
-       GIT_UNUSED(entry);
-       GIT_UNUSED(hidden);
-
-#ifdef GIT_WIN32
        cl_git_mkfile("submod2/hidden_file", "you can't see me");
 
        cl_git_pass(git_win32__hidden(&hidden, "submod2/hidden_file"));
index 547fb7d9577e37b42a839d5395c76f0171b45d3b..82ee363f9f7b98c19dd9fca6158200b306e8c870 100644 (file)
@@ -1024,7 +1024,7 @@ static void create_paths(const char *root, int depth)
        int i;
 
        cl_git_pass(git_buf_puts(&fullpath, root));
-       cl_git_pass(git_buf_putc(&fullpath, '/'));
+       cl_git_pass(git_path_to_dir(&fullpath));
 
        root_len = fullpath.size;
 
index e2ab05c99e0cae21a7d5b814234367480681ee4a..ba3b3a2f6dbf9a645d5027c49136eb210e284ed5 100644 (file)
@@ -2,7 +2,6 @@
 #include "repository.h"
 #include "git2/sys/repository.h"
 #include "mailmap_testdata.h"
-#include "buf_text.h"
 
 static git_repository *g_repo;
 static git_mailmap *g_mailmap;
@@ -109,7 +108,7 @@ void test_mailmap_parsing__windows_string(void)
 
        /* Parse with windows-style line endings */
        git_buf_attach_notowned(&unixbuf, string_mailmap, strlen(string_mailmap));
-       cl_git_pass(git_buf_text_lf_to_crlf(&winbuf, &unixbuf));
+       cl_git_pass(git_buf_lf_to_crlf(&winbuf, &unixbuf));
 
        cl_git_pass(git_mailmap_from_buffer(&g_mailmap, winbuf.ptr, winbuf.size));
        git_buf_dispose(&winbuf);
index 00b2bae024ab5e7ba78f3c9982d1e4539f5db66c..56751c288691759c99553cd3b7c2e7021efb9a19 100644 (file)
@@ -1,6 +1,10 @@
 #include "clar_libgit2.h"
 #include "clar_libgit2_trace.h"
 
+#ifdef GIT_WIN32_LEAKCHECK
+# include "win32/w32_leakcheck.h"
+#endif
+
 #ifdef _WIN32
 int __cdecl main(int argc, char *argv[])
 #else
@@ -14,7 +18,9 @@ int main(int argc, char *argv[])
 
        res = git_libgit2_init();
        if (res < 0) {
-               fprintf(stderr, "failed to init libgit2");
+               const git_error *err = git_error_last();
+               const char *msg = err ? err->message : "unknown failure";
+               fprintf(stderr, "failed to init libgit2: %s\n", msg);
                return res;
        }
 
@@ -29,6 +35,11 @@ int main(int argc, char *argv[])
        cl_global_trace_disable();
        git_libgit2_shutdown();
 
+#ifdef GIT_WIN32_LEAKCHECK
+       if (git_win32_leakcheck_has_leaks())
+               res = res || 1;
+#endif
+
        at_exit_cmd = getenv("CLAR_AT_EXIT");
        if (at_exit_cmd != NULL) {
                int at_exit = system(at_exit_cmd);
index ad29fcd9424f6f9ff84a2b9c26a87fd035f60bc6..0b85f271244342dde0b6615f599cdafa530a3db9 100644 (file)
@@ -49,7 +49,7 @@ static bool test_file_contents(const char *filename, const char *expected)
        git_buf file_path_buf = GIT_BUF_INIT, file_buf = GIT_BUF_INIT;
        bool equals;
        
-       git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename);
+       git_buf_joinpath(&file_path_buf, git_repository_path(repo), filename);
        
        cl_git_pass(git_futils_readbuffer(&file_buf, file_path_buf.ptr));
        equals = (strcmp(file_buf.ptr, expected) == 0);
@@ -64,7 +64,7 @@ static void write_file_contents(const char *filename, const char *output)
 {
        git_buf file_path_buf = GIT_BUF_INIT;
 
-       git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo),
+       git_buf_joinpath(&file_path_buf, git_repository_path(repo),
                filename);
        cl_git_rewritefile(file_path_buf.ptr, output);
 
diff --git a/tests/network/joinpath.c b/tests/network/joinpath.c
deleted file mode 100644 (file)
index da8393b..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-#include "clar_libgit2.h"
-#include "net.h"
-#include "netops.h"
-
-static git_net_url source, target;
-
-void test_network_joinpath__initialize(void)
-{
-       memset(&source, 0, sizeof(source));
-       memset(&target, 0, sizeof(target));
-}
-
-void test_network_joinpath__cleanup(void)
-{
-       git_net_url_dispose(&source);
-       git_net_url_dispose(&target);
-}
-
-void test_network_joinpath__target_paths_and_queries(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
-       cl_assert_equal_s(target.path, "/a/b/c/d");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
-       cl_assert_equal_s(target.path, "/a/b/c/d");
-       cl_assert_equal_s(target.query, "foo");
-       git_net_url_dispose(&target);
-}
-
-void test_network_joinpath__source_query_removed(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b?query&one&two"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
-       cl_assert_equal_s(target.path, "/a/b/c/d");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
-       cl_assert_equal_s(target.path, "/a/b/c/d");
-       cl_assert_equal_s(target.query, "foo");
-       git_net_url_dispose(&target);
-}
-
-void test_network_joinpath__source_lacks_path(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-}
-
-void test_network_joinpath__source_is_slash(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com/"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-}
-
-
-void test_network_joinpath__source_has_query(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com?query"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
-       cl_assert_equal_s(target.path, "/");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
-       cl_assert_equal_s(target.path, "/asdf");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
-       cl_assert_equal_s(target.path, "/foo/bar");
-       cl_assert_equal_s(target.query, "hello");
-       git_net_url_dispose(&target);
-}
-
-
-void test_network_joinpath__empty_query_ignored(void)
-{
-       cl_git_pass(git_net_url_parse(&source, "http://example.com/foo"));
-
-       cl_git_pass(git_net_url_joinpath(&target, &source, "/bar/baz?"));
-       cl_assert_equal_s(target.path, "/foo/bar/baz");
-       cl_assert_equal_p(target.query, NULL);
-       git_net_url_dispose(&target);
-}
diff --git a/tests/network/redirect.c b/tests/network/redirect.c
deleted file mode 100644 (file)
index 7ce1310..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "clar_libgit2.h"
-#include "net.h"
-#include "netops.h"
-
-static git_net_url conndata;
-
-void test_network_redirect__initialize(void)
-{
-       memset(&conndata, 0, sizeof(conndata));
-}
-
-void test_network_redirect__cleanup(void)
-{
-       git_net_url_dispose(&conndata);
-}
-
-void test_network_redirect__redirect_http(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "http://example.com/foo/bar/baz"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "http://example.com/foo/bar/baz", "bar/baz"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/foo/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-}
-
-void test_network_redirect__redirect_ssl(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://example.com/foo/bar/baz"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "https://example.com/foo/bar/baz", "bar/baz"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/foo/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-}
-
-void test_network_redirect__redirect_leaves_root_path(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://example.com/foo/bar/baz"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "https://example.com/foo/bar/baz", "/foo/bar/baz"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-}
-
-void test_network_redirect__redirect_encoded_username_password(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/foo/");
-       cl_assert_equal_s(conndata.username, "user/name");
-       cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
-}
-
-void test_network_redirect__redirect_cross_host_denied(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
-       cl_git_fail_with(git_net_url_apply_redirect(&conndata,
-                               "https://foo.com/bar/baz", NULL),
-                       -1);
-}
-
-void test_network_redirect__redirect_http_downgrade_denied(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
-       cl_git_fail_with(git_net_url_apply_redirect(&conndata,
-                               "http://foo.com/bar/baz", NULL),
-                       -1);
-}
-
-void test_network_redirect__redirect_relative(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "/zap/baz/biff?bam", NULL));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "foo.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-}
-
-void test_network_redirect__redirect_relative_ssl(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "/zap/baz/biff?bam", NULL));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "foo.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-}
-
-void test_network_redirect__service_query_no_query_params_in_location(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "/baz/info/refs", "/info/refs?service=git-upload-pack"));
-       cl_assert_equal_s(conndata.path, "/baz");
-}
-
-void test_network_redirect__service_query_with_query_params_in_location(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
-       cl_git_pass(git_net_url_apply_redirect(&conndata,
-                               "/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
-       cl_assert_equal_s(conndata.path, "/baz");
-}
index 5c8eb1502e60e696e29c8876ac175d87e3a3b951..d9e0d9e8dd7a08a7fbebec1be84df784c21b8c87 100644 (file)
@@ -13,7 +13,7 @@ static void assert_refspec(unsigned int direction, const char *input, bool is_ex
        if (is_expected_to_be_valid)
                cl_assert_equal_i(0, error);
        else
-               cl_assert_equal_i(GIT_ERROR, error);
+               cl_assert_equal_i(GIT_EINVALIDSPEC, error);
 }
 
 void test_network_refspecs__parsing(void)
index c26fbd0a5b9f800b7f69b36dbfb9ec9c7f8ccdec..a3080f67c038439f24e2bf20df9ac39dde2773be 100644 (file)
@@ -1,17 +1,24 @@
 #include "clar_libgit2.h"
 
+static int is_valid_name(const char *name)
+{
+       int valid = 0;
+       cl_git_pass(git_remote_name_is_valid(&valid, name));
+       return valid;
+}
+
 void test_network_remote_isvalidname__can_detect_invalid_formats(void)
 {
-       cl_assert_equal_i(false, git_remote_is_valid_name("/"));
-       cl_assert_equal_i(false, git_remote_is_valid_name("//"));
-       cl_assert_equal_i(false, git_remote_is_valid_name(".lock"));
-       cl_assert_equal_i(false, git_remote_is_valid_name("a.lock"));
-       cl_assert_equal_i(false, git_remote_is_valid_name("/no/leading/slash"));
-       cl_assert_equal_i(false, git_remote_is_valid_name("no/trailing/slash/"));
+       cl_assert_equal_i(false, is_valid_name("/"));
+       cl_assert_equal_i(false, is_valid_name("//"));
+       cl_assert_equal_i(false, is_valid_name(".lock"));
+       cl_assert_equal_i(false, is_valid_name("a.lock"));
+       cl_assert_equal_i(false, is_valid_name("/no/leading/slash"));
+       cl_assert_equal_i(false, is_valid_name("no/trailing/slash/"));
 }
 
 void test_network_remote_isvalidname__wont_hopefully_choke_on_valid_formats(void)
 {
-       cl_assert_equal_i(true, git_remote_is_valid_name("webmatrix"));
-       cl_assert_equal_i(true, git_remote_is_valid_name("yishaigalatzer/rules"));
+       cl_assert_equal_i(true, is_valid_name("webmatrix"));
+       cl_assert_equal_i(true, is_valid_name("yishaigalatzer/rules"));
 }
index 0694a6f66d18666de907e37779b22490f7d8c904..ed6a890751fd1e0336f1a8f07858e7ef39677cc2 100644 (file)
@@ -56,6 +56,49 @@ void test_network_remote_remotes__parsing(void)
        git_buf_dispose(&url);
 }
 
+static int remote_ready_callback(git_remote *remote, int direction, void *payload)
+{
+       if (direction == GIT_DIRECTION_PUSH) {
+               const char *url = git_remote_pushurl(remote);
+
+               cl_assert_equal_p(url, NULL);;
+               cl_assert_equal_s(payload, "payload");
+               return git_remote_set_instance_pushurl(remote, "push_url");
+       }
+
+       if (direction == GIT_DIRECTION_FETCH) {
+               const char *url = git_remote_url(remote);
+
+               cl_assert_equal_s(url, "git://github.com/libgit2/libgit2");
+               cl_assert_equal_s(payload, "payload");
+               return git_remote_set_instance_url(remote, "fetch_url");
+       }
+
+       return -1;
+}
+
+void test_network_remote_remotes__remote_ready(void)
+{
+       git_buf url = GIT_BUF_INIT;
+
+       git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+       callbacks.remote_ready = remote_ready_callback;
+       callbacks.payload = "payload";
+
+       cl_assert_equal_s(git_remote_name(_remote), "test");
+       cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
+       cl_assert(git_remote_pushurl(_remote) == NULL);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks));
+       cl_assert_equal_s(url.ptr, "fetch_url");
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
+       cl_assert_equal_s(url.ptr, "push_url");
+
+       git_buf_dispose(&url);
+}
+
+#ifndef GIT_DEPRECATE_HARD
 static int urlresolve_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
 {
        cl_assert(strcmp(url, "git://github.com/libgit2/libgit2") == 0);
@@ -69,9 +112,11 @@ static int urlresolve_callback(git_buf *url_resolved, const char *url, int direc
 
        return GIT_OK;
 }
+#endif
 
 void test_network_remote_remotes__urlresolve(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_buf url = GIT_BUF_INIT;
 
        git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
@@ -89,8 +134,10 @@ void test_network_remote_remotes__urlresolve(void)
        cl_assert_equal_s(url.ptr, "pushresolve");
 
        git_buf_dispose(&url);
+#endif
 }
 
+#ifndef GIT_DEPRECATE_HARD
 static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
 {
        GIT_UNUSED(url_resolved);
@@ -99,9 +146,11 @@ static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *ur
        GIT_UNUSED(payload);
        return GIT_PASSTHROUGH;
 }
+#endif
 
 void test_network_remote_remotes__urlresolve_passthrough(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_buf url = GIT_BUF_INIT;
        const char *orig_url = "git://github.com/libgit2/libgit2";
 
@@ -118,6 +167,52 @@ void test_network_remote_remotes__urlresolve_passthrough(void)
        cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
        cl_assert_equal_s(url.ptr, orig_url);
 
+       git_buf_dispose(&url);
+#endif
+}
+
+void test_network_remote_remotes__instance_url(void)
+{
+       git_buf url = GIT_BUF_INIT;
+       const char *orig_url = "git://github.com/libgit2/libgit2";
+
+       cl_assert_equal_s(git_remote_name(_remote), "test");
+       cl_assert_equal_s(git_remote_url(_remote), orig_url);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
+       cl_assert_equal_s(url.ptr, orig_url);
+       git_buf_clear(&url);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
+       cl_assert_equal_s(url.ptr, orig_url);
+       git_buf_clear(&url);
+
+       /* Setting the instance url updates the fetch and push URLs */
+       git_remote_set_instance_url(_remote, "https://github.com/new/remote/url");
+       cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
+       cl_assert_equal_p(git_remote_pushurl(_remote), NULL);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
+       cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
+       git_buf_clear(&url);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
+       cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
+       git_buf_clear(&url);
+
+       /* Setting the instance push url updates only the push URL */
+       git_remote_set_instance_pushurl(_remote, "https://github.com/new/push/url");
+       cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
+       cl_assert_equal_s(git_remote_pushurl(_remote), "https://github.com/new/push/url");
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
+       cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
+       git_buf_clear(&url);
+
+       cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
+       cl_assert_equal_s(url.ptr, "https://github.com/new/push/url");
+       git_buf_clear(&url);
+
        git_buf_dispose(&url);
 }
 
diff --git a/tests/network/url/joinpath.c b/tests/network/url/joinpath.c
new file mode 100644 (file)
index 0000000..bf45571
--- /dev/null
@@ -0,0 +1,194 @@
+#include "clar_libgit2.h"
+#include "net.h"
+#include "netops.h"
+
+static git_net_url source, target;
+
+void test_network_url_joinpath__initialize(void)
+{
+       memset(&source, 0, sizeof(source));
+       memset(&target, 0, sizeof(target));
+}
+
+void test_network_url_joinpath__cleanup(void)
+{
+       git_net_url_dispose(&source);
+       git_net_url_dispose(&target);
+}
+
+void test_network_url_joinpath__target_paths_and_queries(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
+       cl_assert_equal_s(target.path, "/a/b/c/d");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
+       cl_assert_equal_s(target.path, "/a/b/c/d");
+       cl_assert_equal_s(target.query, "foo");
+       git_net_url_dispose(&target);
+}
+
+void test_network_url_joinpath__source_query_removed(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b?query&one&two"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
+       cl_assert_equal_s(target.path, "/a/b/c/d");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
+       cl_assert_equal_s(target.path, "/a/b/c/d");
+       cl_assert_equal_s(target.query, "foo");
+       git_net_url_dispose(&target);
+}
+
+void test_network_url_joinpath__source_lacks_path(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+}
+
+void test_network_url_joinpath__source_is_slash(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com/"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+}
+
+
+void test_network_url_joinpath__source_has_query(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com?query"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+       cl_assert_equal_s(target.path, "/");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+       cl_assert_equal_s(target.path, "/asdf");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+       cl_assert_equal_s(target.path, "/foo/bar");
+       cl_assert_equal_s(target.query, "hello");
+       git_net_url_dispose(&target);
+}
+
+
+void test_network_url_joinpath__empty_query_ignored(void)
+{
+       cl_git_pass(git_net_url_parse(&source, "http://example.com/foo"));
+
+       cl_git_pass(git_net_url_joinpath(&target, &source, "/bar/baz?"));
+       cl_assert_equal_s(target.path, "/foo/bar/baz");
+       cl_assert_equal_p(target.query, NULL);
+       git_net_url_dispose(&target);
+}
diff --git a/tests/network/url/parse.c b/tests/network/url/parse.c
new file mode 100644 (file)
index 0000000..edfd6ab
--- /dev/null
@@ -0,0 +1,557 @@
+#include "clar_libgit2.h"
+#include "net.h"
+
+static git_net_url conndata;
+
+void test_network_url_parse__initialize(void)
+{
+       memset(&conndata, 0, sizeof(conndata));
+}
+
+void test_network_url_parse__cleanup(void)
+{
+       git_net_url_dispose(&conndata);
+}
+
+/* Hostname */
+
+void test_network_url_parse__hostname_trivial(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com/"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_implied_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_implied_root_custom_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:42"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "42");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__hostname_implied_root_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_encoded_password(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user:pass%2fis%40bad@hostname.com:1234/"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "hostname.com");
+       cl_assert_equal_s(conndata.port, "1234");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass/is@bad");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__hostname_user(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user@example.com/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_user_pass(void)
+{
+       /* user:pass@hostname.tld/resource */
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user:pass@example.com/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_port(void)
+{
+       /* hostname.tld:port/resource */
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://example.com:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__hostname_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__hostname_user_port(void)
+{
+       /* user@hostname.tld:port/resource */
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user@example.com:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__hostname_user_pass_port(void)
+{
+       /* user:pass@hostname.tld:port/resource */
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user:pass@example.com:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+/* IPv4 addresses */
+
+void test_network_url_parse__ipv4_trivial(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_implied_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_implied_root_custom_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:42"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "42");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv4_implied_root_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_encoded_password(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass%2fis%40bad@192.168.1.1:1234/"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "1234");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass/is@bad");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv4_user(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user@192.168.1.1/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_user_pass(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass@192.168.1.1/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://192.168.1.1:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv4_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv4_user_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user@192.168.1.1:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv4_user_pass_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass@192.168.1.1:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "192.168.1.1");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+/* IPv6 addresses */
+
+void test_network_url_parse__ipv6_trivial(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_implied_root(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_implied_root_custom_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:42"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "42");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv6_implied_root_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_encoded_password(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001]:1234/"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "1234");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass/is@bad");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv6_user(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user@[fe80::dcad:beff:fe00:0001]/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_user_pass(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass@[fe80::dcad:beff:fe00:0001]/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://[fe80::dcad:beff:fe00:0001]:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv6_empty_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:/resource"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
+}
+
+void test_network_url_parse__ipv6_user_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user@[fe80::dcad:beff:fe00:0001]:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_p(conndata.password, NULL);
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv6_user_pass_port(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+               "https://user:pass@[fe80::dcad:beff:fe00:0001]:9191/resource"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001");
+       cl_assert_equal_s(conndata.port, "9191");
+       cl_assert_equal_s(conndata.path, "/resource");
+       cl_assert_equal_s(conndata.username, "user");
+       cl_assert_equal_s(conndata.password, "pass");
+       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
+}
+
+void test_network_url_parse__ipv6_invalid_addresses(void)
+{
+       /* Opening bracket missing */
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]:42"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]:"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001]:1234/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@fe80::dcad:beff:fe00:0001]/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@fe80::dcad:beff:fe00:0001]/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://fe80::dcad:beff:fe00:0001]:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001]:/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@fe80::dcad:beff:fe00:0001]:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@fe80::dcad:beff:fe00:0001]:9191/resource"));
+
+       /* Closing bracket missing */
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001:42"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001:"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001:1234/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@[fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@[fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://[fe80::dcad:beff:fe00:0001:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://[fe80::dcad:beff:fe00:0001:/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@[fe80::dcad:beff:fe00:0001:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@[fe80::dcad:beff:fe00:0001:9191/resource"));
+       /* Both brackets missing */
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001:42"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001:"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001:1234/"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@fe80::dcad:beff:fe00:0001/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://fe80::dcad:beff:fe00:0001:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "http://fe80::dcad:beff:fe00:0001:/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user@fe80::dcad:beff:fe00:0001:9191/resource"));
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata,
+               "https://user:pass@fe80::dcad:beff:fe00:0001:9191/resource"));
+
+       /* Invalid chracter inside address */
+       cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, "http://[fe8o::dcad:beff:fe00:0001]/resource"));
+}
diff --git a/tests/network/url/pattern.c b/tests/network/url/pattern.c
new file mode 100644 (file)
index 0000000..5e4495f
--- /dev/null
@@ -0,0 +1,103 @@
+#include "clar_libgit2.h"
+#include "net.h"
+
+struct url_pattern {
+       const char *url;
+       const char *pattern;
+       bool matches;
+};
+
+void test_network_url_pattern__single(void)
+{
+       git_net_url url;
+       size_t i;
+
+       struct url_pattern url_patterns[] = {
+               /* Wildcard matches */
+               { "https://example.com/", "", false },
+               { "https://example.com/", "*", true },
+
+               /* Literal and wildcard matches */
+               { "https://example.com/", "example.com", true },
+               { "https://example.com/", ".example.com", true },
+               { "https://example.com/", "*.example.com", true },
+               { "https://www.example.com/", "www.example.com", true },
+               { "https://www.example.com/", ".example.com", true },
+               { "https://www.example.com/", "*.example.com", true },
+
+               /* Literal and wildcard failures */
+               { "https://example.com/", "example.org", false },
+               { "https://example.com/", ".example.org", false },
+               { "https://example.com/", "*.example.org", false },
+               { "https://foo.example.com/", "www.example.com", false },
+
+               /*
+                * A port in the pattern is optional; if no port is
+                * present, it matches *all* ports.
+                */
+               { "https://example.com/", "example.com:443", true },
+               { "https://example.com/", "example.com:80", false },
+               { "https://example.com:1443/", "example.com", true },
+
+               /* Failures with similar prefix/suffix */
+               { "https://texample.com/", "example.com", false },
+               { "https://example.com/", "mexample.com", false },
+               { "https://example.com:44/", "example.com:443", false },
+               { "https://example.com:443/", "example.com:44", false },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(url_patterns); i++) {
+               cl_git_pass(git_net_url_parse(&url, url_patterns[i].url));
+               cl_assert_(git_net_url_matches_pattern(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern);
+               git_net_url_dispose(&url);
+       }
+}
+
+void test_network_url_pattern__list(void)
+{
+       git_net_url url;
+       size_t i;
+
+       struct url_pattern url_patterns[] = {
+               /* Wildcard matches */
+               { "https://example.com/", "", false },
+               { "https://example.com/", "*", true },
+               { "https://example.com/", ",example.com,", true },
+               { "https://example.com/", "foo,,example.com,,bar", true },
+               { "https://example.com/", "foo,,zzz,,*,,bar", true },
+
+               /* Literals */
+               { "https://example.com/", "example.com", true },
+               { "https://example.com/", "foo.bar,example.com", true },
+               { "https://example.com/", "foo.bar", false },
+               { "https://example.com/", "foo.bar,example.org", false },
+               { "https://www.example.com/", "foo.example.com,www.example.com,bar.example.com", true },
+               { "https://www.example.com/", "foo.example.com,baz.example.com,bar.example.com", false },
+               { "https://foo.example.com/", "www.example.com", false },
+               { "https://foo.example.com/", "bar.example.com,www.example.com,", false },
+
+               /* Wildcards */
+               { "https://example.com/", ".example.com", true },
+               { "https://example.com/", "*.example.com", true },
+               { "https://example.com/", "foo.com,bar.com,.example.com", true },
+               { "https://example.com/", ".foo.com,.bar.com,.example.com", true },
+               { "https://example.com/", ".foo.com,.bar.com,asdf.com", false },
+               { "https://example.com/", "*.foo,*.bar,*.example.com,*.asdf", true },
+               { "https://example.com/", "*.foo,*.bar,*.asdf", false },
+
+
+               /* Ports! */
+               { "https://example.com/", "example.com:443", true },
+               { "https://example.com/", "example.com:42,example.com:443,example.com:99", true },
+               { "https://example.com/", "example.com:42,example.com:80,example.org:443", false },
+               { "https://example.com:1443/", "example.com", true },
+               { "https://example.com:44/", "example.com:443", false },
+               { "https://example.com:443/", "example.com:44", false },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(url_patterns); i++) {
+               cl_git_pass(git_net_url_parse(&url, url_patterns[i].url));
+               cl_assert_(git_net_url_matches_pattern_list(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern);
+               git_net_url_dispose(&url);
+       }
+}
diff --git a/tests/network/url/redirect.c b/tests/network/url/redirect.c
new file mode 100644 (file)
index 0000000..2c0b614
--- /dev/null
@@ -0,0 +1,129 @@
+#include "clar_libgit2.h"
+#include "net.h"
+#include "netops.h"
+
+static git_net_url conndata;
+
+void test_network_url_redirect__initialize(void)
+{
+       memset(&conndata, 0, sizeof(conndata));
+}
+
+void test_network_url_redirect__cleanup(void)
+{
+       git_net_url_dispose(&conndata);
+}
+
+void test_network_url_redirect__redirect_http(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "http://example.com/foo/bar/baz"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "http://example.com/foo/bar/baz", "bar/baz"));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/foo/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_url_redirect__redirect_ssl(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://example.com/foo/bar/baz"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "https://example.com/foo/bar/baz", "bar/baz"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/foo/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_url_redirect__redirect_leaves_root_path(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://example.com/foo/bar/baz"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "https://example.com/foo/bar/baz", "/foo/bar/baz"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_url_redirect__redirect_encoded_username_password(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata,
+                               "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "example.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/foo/");
+       cl_assert_equal_s(conndata.username, "user/name");
+       cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
+}
+
+void test_network_url_redirect__redirect_cross_host_denied(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
+       cl_git_fail_with(git_net_url_apply_redirect(&conndata,
+                               "https://foo.com/bar/baz", NULL),
+                       -1);
+}
+
+void test_network_url_redirect__redirect_http_downgrade_denied(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
+       cl_git_fail_with(git_net_url_apply_redirect(&conndata,
+                               "http://foo.com/bar/baz", NULL),
+                       -1);
+}
+
+void test_network_url_redirect__redirect_relative(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "/zap/baz/biff?bam", NULL));
+       cl_assert_equal_s(conndata.scheme, "http");
+       cl_assert_equal_s(conndata.host, "foo.com");
+       cl_assert_equal_s(conndata.port, "80");
+       cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_url_redirect__redirect_relative_ssl(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "/zap/baz/biff?bam", NULL));
+       cl_assert_equal_s(conndata.scheme, "https");
+       cl_assert_equal_s(conndata.host, "foo.com");
+       cl_assert_equal_s(conndata.port, "443");
+       cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
+       cl_assert_equal_p(conndata.username, NULL);
+       cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_url_redirect__service_query_no_query_params_in_location(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "/baz/info/refs", "/info/refs?service=git-upload-pack"));
+       cl_assert_equal_s(conndata.path, "/baz");
+}
+
+void test_network_url_redirect__service_query_with_query_params_in_location(void)
+{
+       cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
+       cl_git_pass(git_net_url_apply_redirect(&conndata,
+                               "/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
+       cl_assert_equal_s(conndata.path, "/baz");
+}
diff --git a/tests/network/urlparse.c b/tests/network/urlparse.c
deleted file mode 100644 (file)
index 1570788..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-#include "clar_libgit2.h"
-#include "net.h"
-
-static git_net_url conndata;
-
-void test_network_urlparse__initialize(void)
-{
-       memset(&conndata, 0, sizeof(conndata));
-}
-
-void test_network_urlparse__cleanup(void)
-{
-       git_net_url_dispose(&conndata);
-}
-
-void test_network_urlparse__trivial(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__root(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com/"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__implied_root(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__implied_root_custom_port(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:42"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "42");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
-}
-
-void test_network_urlparse__implied_root_empty_port(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__encoded_password(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user:pass%2fis%40bad@hostname.com:1234/"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "hostname.com");
-       cl_assert_equal_s(conndata.port, "1234");
-       cl_assert_equal_s(conndata.path, "/");
-       cl_assert_equal_s(conndata.username, "user");
-       cl_assert_equal_s(conndata.password, "pass/is@bad");
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
-}
-
-void test_network_urlparse__user(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user@example.com/resource"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_s(conndata.username, "user");
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__user_pass(void)
-{
-       /* user:pass@hostname.tld/resource */
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user:pass@example.com/resource"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "443");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_s(conndata.username, "user");
-       cl_assert_equal_s(conndata.password, "pass");
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__port(void)
-{
-       /* hostname.tld:port/resource */
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://example.com:9191/resource"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "9191");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
-}
-
-void test_network_urlparse__empty_port(void)
-{
-       cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource"));
-       cl_assert_equal_s(conndata.scheme, "http");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "80");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_p(conndata.username, NULL);
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
-}
-
-void test_network_urlparse__user_port(void)
-{
-       /* user@hostname.tld:port/resource */
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user@example.com:9191/resource"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "9191");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_s(conndata.username, "user");
-       cl_assert_equal_p(conndata.password, NULL);
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
-}
-
-void test_network_urlparse__user_pass_port(void)
-{
-       /* user:pass@hostname.tld:port/resource */
-       cl_git_pass(git_net_url_parse(&conndata,
-                               "https://user:pass@example.com:9191/resource"));
-       cl_assert_equal_s(conndata.scheme, "https");
-       cl_assert_equal_s(conndata.host, "example.com");
-       cl_assert_equal_s(conndata.port, "9191");
-       cl_assert_equal_s(conndata.path, "/resource");
-       cl_assert_equal_s(conndata.username, "user");
-       cl_assert_equal_s(conndata.password, "pass");
-       cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
-}
index 0f0f4845f392e82edb1ddc268678f69f1b8806d7..a8e3d3097b8caea93d4e18f35261b9980e72cee5 100644 (file)
@@ -1,7 +1,6 @@
 #include "clar_libgit2.h"
 #include "posix.h"
 #include "blob.h"
-#include "buf_text.h"
 
 static git_repository *g_repo = NULL;
 
@@ -44,9 +43,9 @@ static git_buf_text_stats g_crlf_filtered_stats[CRLF_NUM_TEST_OBJECTS] = {
        { 0, 0, 2, 2, 2, 6, 0 },
        { 0, 0, 4, 4, 1, 31, 0 },
        { 0, 1, 1, 2, 1, 9, 5 },
-       { GIT_BOM_UTF8, 0, 0, 1, 0, 16, 0 },
-       { GIT_BOM_UTF8, 0, 2, 2, 2, 27, 0 },
-       { GIT_BOM_UTF16_BE, 5, 0, 0, 0, 7, 5 },
+       { GIT_BUF_BOM_UTF8, 0, 0, 1, 0, 16, 0 },
+       { GIT_BUF_BOM_UTF8, 0, 2, 2, 2, 27, 0 },
+       { GIT_BUF_BOM_UTF16_BE, 5, 0, 0, 0, 7, 5 },
 };
 
 void test_object_blob_filter__initialize(void)
@@ -97,7 +96,7 @@ void test_object_blob_filter__stats(void)
        for (i = 0; i < CRLF_NUM_TEST_OBJECTS; i++) {
                cl_git_pass(git_blob_lookup(&blob, g_repo, &g_crlf_oids[i]));
                cl_git_pass(git_blob__getbuf(&buf, blob));
-               git_buf_text_gather_stats(&stats, &buf, false);
+               git_buf_gather_text_stats(&stats, &buf, false);
                cl_assert_equal_i(
                        0, memcmp(&g_crlf_filtered_stats[i], &stats, sizeof(stats)));
                git_blob_free(blob);
index 8a1a2d26d2df36e66d0c63c55c3e0199eb77b12f..d15f09205c52c1f9b8a7c2fa858520faaf6c274c 100644 (file)
@@ -20,7 +20,7 @@ static void ensure_tag_pattern_match(git_repository *repo,
        int already_found[MAX_USED_TAGS] = { 0 };
        git_strarray tag_list;
        int error = 0;
-       size_t sucessfully_found = 0;
+       size_t successfully_found = 0;
        size_t i, j;
 
        cl_assert(data->expected_matches <= MAX_USED_TAGS);
@@ -42,12 +42,12 @@ static void ensure_tag_pattern_match(git_repository *repo,
                        if (!already_found[j] && !strcmp(data->expected_results[j], tag_list.strings[i]))
                        {
                                already_found[j] = 1;
-                               sucessfully_found++;
+                               successfully_found++;
                                break;
                        }
                }
        }
-       cl_assert_equal_i((int)sucessfully_found, (int)data->expected_matches);
+       cl_assert_equal_i((int)successfully_found, (int)data->expected_matches);
 
 exit:
        git_strarray_dispose(&tag_list);
index 7a45a57ae9340865cb8bac1025f26e0c5b2242cf..02112380b80424efcf4bae4973e0af712b5b48f7 100644 (file)
@@ -127,7 +127,7 @@ void test_odb_foreach__files_in_objects_dir(void)
        cl_fixture_sandbox("testrepo.git");
        cl_git_pass(git_repository_open(&repo, "testrepo.git"));
 
-       cl_git_pass(git_buf_printf(&buf, "%s/objects/somefile", git_repository_path(repo)));
+       cl_git_pass(git_buf_joinpath(&buf, git_repository_path(repo), "objects/somefile"));
        cl_git_mkfile(buf.ptr, "");
        git_buf_dispose(&buf);
 
index 6af8b0d1b86e69b9ea238bc8bb3516eef0b0ad37..e027230fac06fd58c3e81a034c40f900bdcc02ee 100644 (file)
@@ -1,5 +1,6 @@
 #include "clar_libgit2.h"
 #include "git2/sys/odb_backend.h"
+#include "odb.h"
 
 typedef struct {
        git_odb_backend base;
@@ -43,6 +44,11 @@ void test_odb_sorting__cleanup(void)
 {
        git_odb_free(_odb);
        _odb = NULL;
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY,
+                                    GIT_ODB_DEFAULT_LOOSE_PRIORITY));
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_PACKED_PRIORITY,
+                                    GIT_ODB_DEFAULT_PACKED_PRIORITY));
 }
 
 void test_odb_sorting__basic_backends_sorting(void)
@@ -68,3 +74,26 @@ void test_odb_sorting__alternate_backends_sorting(void)
 
        check_backend_sorting(_odb);
 }
+
+void test_odb_sorting__override_default_backend_priority(void)
+{
+       git_odb *new_odb;
+       git_odb_backend *loose, *packed, *backend;
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY, 5));
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ODB_PACKED_PRIORITY, 3));
+       git_odb_backend_pack(&packed, "./testrepo.git/objects");
+       git_odb_backend_loose(&loose, "./testrepo.git/objects", -1, 0, 0, 0);
+
+       cl_git_pass(git_odb_open(&new_odb, cl_fixture("testrepo.git/objects")));
+       cl_assert_equal_sz(2, git_odb_num_backends(new_odb));
+
+       cl_git_pass(git_odb_get_backend(&backend, new_odb, 0));
+       cl_assert_equal_p(loose->read, backend->read);
+
+       cl_git_pass(git_odb_get_backend(&backend, new_odb, 1));
+       cl_assert_equal_p(packed->read, backend->read);
+
+       git_odb_free(new_odb);
+       loose->free(loose);
+       packed->free(packed);
+}
index 6524fcd8eeec97da0d9c4f932b9bab2670e10985..6735e9cdb31a9f7b07562b19bd6c6eb7caabd8fc 100644 (file)
@@ -67,14 +67,9 @@ void test_online_badssl__old_cipher(void)
        git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
        opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid;
 
-       /* FIXME: we don't actually reject RC4 anywhere, figure out what to tweak */
-       cl_skip();
-
        if (!g_has_ssl)
                cl_skip();
 
-       cl_git_fail_with(GIT_ECERTIFICATE,
-                        git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL));
-       cl_git_fail_with(GIT_ECERTIFICATE,
-                        git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts));
+       cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL));
+       cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts));
 }
index c62baac2d75ddfd62c552276219251ba173dc6dc..7d43c6a098f8132c986ec8aa41ca40e1bb1282af 100644 (file)
@@ -36,6 +36,7 @@ static char *_remote_expectcontinue = NULL;
 static int _orig_proxies_need_reset = 0;
 static char *_orig_http_proxy = NULL;
 static char *_orig_https_proxy = NULL;
+static char *_orig_no_proxy = NULL;
 
 static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload)
 {
@@ -110,10 +111,14 @@ void test_online_clone__cleanup(void)
        if (_orig_proxies_need_reset) {
                cl_setenv("HTTP_PROXY", _orig_http_proxy);
                cl_setenv("HTTPS_PROXY", _orig_https_proxy);
+               cl_setenv("NO_PROXY", _orig_no_proxy);
 
                git__free(_orig_http_proxy);
                git__free(_orig_https_proxy);
+               git__free(_orig_no_proxy);
        }
+
+       git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL);
 }
 
 void test_online_clone__network_full(void)
@@ -852,6 +857,7 @@ void test_online_clone__proxy_credentials_in_environment(void)
 
        _orig_http_proxy = cl_getenv("HTTP_PROXY");
        _orig_https_proxy = cl_getenv("HTTPS_PROXY");
+       _orig_no_proxy = cl_getenv("NO_PROXY");
        _orig_proxies_need_reset = 1;
 
        g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
@@ -863,12 +869,35 @@ void test_online_clone__proxy_credentials_in_environment(void)
 
        cl_setenv("HTTP_PROXY", url.ptr);
        cl_setenv("HTTPS_PROXY", url.ptr);
+       cl_setenv("NO_PROXY", NULL);
 
        cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
 
        git_buf_dispose(&url);
 }
 
+void test_online_clone__proxy_credentials_in_url_https(void)
+{
+       git_buf url = GIT_BUF_INIT;
+
+       if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
+               cl_skip();
+
+       cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
+               _remote_proxy_scheme ? _remote_proxy_scheme : "http",
+               _remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
+
+       g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
+       g_options.fetch_opts.proxy_opts.url = url.ptr;
+       g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
+       g_options.fetch_opts.callbacks.certificate_check = ssl_cert;
+       called_proxy_creds = 0;
+       cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options));
+       cl_assert(called_proxy_creds == 0);
+
+       git_buf_dispose(&url);
+}
+
 void test_online_clone__proxy_auto_not_detected(void)
 {
        g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
diff --git a/tests/online/customcert.c b/tests/online/customcert.c
new file mode 100644 (file)
index 0000000..c7a0de1
--- /dev/null
@@ -0,0 +1,79 @@
+#include "clar_libgit2.h"
+
+#include "path.h"
+#include "git2/clone.h"
+#include "git2/cred_helpers.h"
+#include "remote.h"
+#include "futils.h"
+#include "refs.h"
+
+/*
+ * Certificate one is in the `certs` folder; certificate two is in the
+ * `self-signed.pem` file.
+ */
+#define CUSTOM_CERT_ONE_URL "https://test.libgit2.org:1443/anonymous/test.git"
+#define CUSTOM_CERT_ONE_PATH "certs"
+
+#define CUSTOM_CERT_TWO_URL "https://test.libgit2.org:2443/anonymous/test.git"
+#define CUSTOM_CERT_TWO_FILE "self-signed.pem"
+
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+static git_repository *g_repo;
+static int initialized = false;
+#endif
+
+void test_online_customcert__initialize(void)
+{
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+       g_repo = NULL;
+
+       if (!initialized) {
+               git_buf path = GIT_BUF_INIT, file = GIT_BUF_INIT;
+               char cwd[GIT_PATH_MAX];
+
+               cl_fixture_sandbox(CUSTOM_CERT_ONE_PATH);
+               cl_fixture_sandbox(CUSTOM_CERT_TWO_FILE);
+
+               cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX));
+               cl_git_pass(git_buf_joinpath(&path, cwd, CUSTOM_CERT_ONE_PATH));
+               cl_git_pass(git_buf_joinpath(&file, cwd, CUSTOM_CERT_TWO_FILE));
+
+               cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS,
+                                            file.ptr, path.ptr));
+               initialized = true;
+
+               git_buf_dispose(&file);
+               git_buf_dispose(&path);
+       }
+#endif
+}
+
+void test_online_customcert__cleanup(void)
+{
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+       if (g_repo) {
+               git_repository_free(g_repo);
+               g_repo = NULL;
+       }
+
+       cl_fixture_cleanup("./cloned");
+       cl_fixture_cleanup(CUSTOM_CERT_ONE_PATH);
+       cl_fixture_cleanup(CUSTOM_CERT_TWO_FILE);
+#endif
+}
+
+void test_online_customcert__file(void)
+{
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+       cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_ONE_URL, "./cloned", NULL));
+       cl_assert(git_path_exists("./cloned/master.txt"));
+#endif
+}
+
+void test_online_customcert__path(void)
+{
+#if (GIT_OPENSSL || GIT_MBEDTLS)
+       cl_git_pass(git_clone(&g_repo, CUSTOM_CERT_TWO_URL, "./cloned", NULL));
+       cl_assert(git_path_exists("./cloned/master.txt"));
+#endif
+}
index f939a16b8b69be6f67ad58cb84c1630b817f9186..67dfd69ed62f6aaaaea64130eae4336abb2d06f3 100644 (file)
@@ -3,9 +3,19 @@
 static git_repository *_repo;
 static int counter;
 
+static char *_remote_proxy_scheme = NULL;
+static char *_remote_proxy_host = NULL;
+static char *_remote_proxy_user = NULL;
+static char *_remote_proxy_pass = NULL;
+
 void test_online_fetch__initialize(void)
 {
        cl_git_pass(git_repository_init(&_repo, "./fetch", 0));
+
+    _remote_proxy_scheme = cl_getenv("GITTEST_REMOTE_PROXY_SCHEME");
+    _remote_proxy_host = cl_getenv("GITTEST_REMOTE_PROXY_HOST");
+    _remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER");
+    _remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
 }
 
 void test_online_fetch__cleanup(void)
@@ -14,6 +24,11 @@ void test_online_fetch__cleanup(void)
        _repo = NULL;
 
        cl_fixture_cleanup("./fetch");
+
+    git__free(_remote_proxy_scheme);
+    git__free(_remote_proxy_host);
+    git__free(_remote_proxy_user);
+    git__free(_remote_proxy_pass);
 }
 
 static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data)
@@ -207,3 +222,28 @@ void test_online_fetch__twice(void)
 
        git_remote_free(remote);
 }
+
+void test_online_fetch__proxy(void)
+{
+    git_remote *remote;
+    git_buf url = GIT_BUF_INIT;
+    git_fetch_options fetch_opts;
+
+    if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
+        cl_skip();
+
+    cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
+        _remote_proxy_scheme ? _remote_proxy_scheme : "http",
+        _remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
+
+    cl_git_pass(git_fetch_options_init(&fetch_opts, GIT_FETCH_OPTIONS_VERSION));
+    fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
+    fetch_opts.proxy_opts.url = url.ptr;
+
+    cl_git_pass(git_remote_create(&remote, _repo, "test", "https://github.com/libgit2/TestGitRepository.git"));
+    cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, &fetch_opts.proxy_opts, NULL));
+    cl_git_pass(git_remote_fetch(remote, NULL, &fetch_opts, NULL));
+
+    git_remote_free(remote);
+    git_buf_dispose(&url);
+}
index fe9af2c43693dbf4d79fe285c3a24ac5baf486ec..b39f7811421c994d8b111cfa2a06c51fe800ea0a 100644 (file)
@@ -58,12 +58,14 @@ int record_update_tips_cb(const char *refname, const git_oid *a, const git_oid *
 int create_deletion_refspecs(git_vector *out, const git_remote_head **heads, size_t heads_len)
 {
        git_buf del_spec = GIT_BUF_INIT;
+       int valid;
        size_t i;
 
        for (i = 0; i < heads_len; i++) {
                const git_remote_head *head = heads[i];
                /* Ignore malformed ref names (which also saves us from tag^{} */
-               if (!git_reference_is_valid_name(head->name))
+               cl_git_pass(git_reference_name_is_valid(&valid, head->name));
+               if (!valid)
                        return 0;
 
                /* Create a refspec that deletes a branch in the remote */
index d829bbc4ad7eaff2606aa0c4e4ce2f1990f3a35c..5f669feaf0c24509d08826eb114f7c613241a2bf 100644 (file)
@@ -12,7 +12,7 @@ extern const git_oid OID_ZERO;
  * @param data pointer to a record_callbacks_data instance
  */
 #define RECORD_CALLBACKS_INIT(data) \
-       { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, data, NULL }
+       { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, NULL, data, NULL }
 
 typedef struct {
        char *name;
index 044679f3bd819a32364fdc38fa35fc99c8c7600a..5e0b77e9bd2cfd4ad8b2775dcc17ed5374e53bd7 100644 (file)
@@ -1,6 +1,5 @@
 #include "clar_libgit2.h"
 #include "mwindow.h"
-#include "global.h"
 
 #include <git2.h>
 #include "git2/sys/commit.h"
@@ -9,6 +8,7 @@
 static size_t expected_open_mwindow_files = 0;
 static size_t original_mwindow_file_limit = 0;
 
+extern git_mutex git__mwindow_mutex;
 extern git_mwindow_ctl git_mwindow__mem_ctl;
 
 void test_pack_filelimit__initialize_tiny(void)
index 1f47d9502b8ef566605eea345f8199152cd3a7a2..d5b91d28ba3635e57d4aaaf522679be47032dd9a 100644 (file)
@@ -1,7 +1,9 @@
 #include "clar_libgit2.h"
 
 #include <git2.h>
+#include <git2/sys/midx.h>
 
+#include "futils.h"
 #include "midx.h"
 
 void test_pack_midx__parse(void)
@@ -15,6 +17,7 @@ void test_pack_midx__parse(void)
        cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
        cl_git_pass(git_buf_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index"));
        cl_git_pass(git_midx_open(&idx, git_buf_cstr(&midx_path)));
+       cl_assert_equal_i(git_midx_needs_refresh(idx, git_buf_cstr(&midx_path)), 0);
 
        cl_git_pass(git_oid_fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5"));
        cl_git_pass(git_midx_entry_find(&e, idx, &id, GIT_OID_HEXSZ));
@@ -27,3 +30,81 @@ void test_pack_midx__parse(void)
        git_repository_free(repo);
        git_buf_dispose(&midx_path);
 }
+
+void test_pack_midx__lookup(void)
+{
+       git_repository *repo;
+       git_commit *commit;
+       git_oid id;
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+
+       cl_git_pass(git_oid_fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5"));
+       cl_git_pass(git_commit_lookup_prefix(&commit, repo, &id, GIT_OID_HEXSZ));
+       cl_assert_equal_s(git_commit_message(commit), "packed commit one\n");
+
+       git_commit_free(commit);
+       git_repository_free(repo);
+}
+
+void test_pack_midx__writer(void)
+{
+       git_repository *repo;
+       git_midx_writer *w = NULL;
+       git_buf midx = GIT_BUF_INIT, expected_midx = GIT_BUF_INIT, path = GIT_BUF_INIT;
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+
+       cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/pack"));
+       cl_git_pass(git_midx_writer_new(&w, git_buf_cstr(&path)));
+
+       cl_git_pass(git_midx_writer_add(w, "pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx"));
+       cl_git_pass(git_midx_writer_add(w, "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx"));
+       cl_git_pass(git_midx_writer_add(w, "pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"));
+
+       cl_git_pass(git_midx_writer_dump(&midx, w));
+       cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/pack/multi-pack-index"));
+       cl_git_pass(git_futils_readbuffer(&expected_midx, git_buf_cstr(&path)));
+
+       cl_assert_equal_i(git_buf_len(&midx), git_buf_len(&expected_midx));
+       cl_assert_equal_strn(git_buf_cstr(&midx), git_buf_cstr(&expected_midx), git_buf_len(&midx));
+
+       git_buf_dispose(&midx);
+       git_buf_dispose(&expected_midx);
+       git_buf_dispose(&path);
+       git_midx_writer_free(w);
+       git_repository_free(repo);
+}
+
+void test_pack_midx__odb_create(void)
+{
+       git_repository *repo;
+       git_odb *odb;
+       git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+       git_buf midx = GIT_BUF_INIT, expected_midx = GIT_BUF_INIT, midx_path = GIT_BUF_INIT;
+       struct stat st;
+
+       opts.bare = true;
+       opts.local = GIT_CLONE_LOCAL;
+       cl_git_pass(git_clone(&repo, cl_fixture("testrepo/.gitted"), "./clone.git", &opts));
+       cl_git_pass(git_buf_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index"));
+       cl_git_fail(p_stat(git_buf_cstr(&midx_path), &st));
+
+       cl_git_pass(git_repository_odb(&odb, repo));
+       cl_git_pass(git_odb_write_multi_pack_index(odb));
+       git_odb_free(odb);
+
+       cl_git_pass(p_stat(git_buf_cstr(&midx_path), &st));
+
+       cl_git_pass(git_futils_readbuffer(&expected_midx, cl_fixture("testrepo.git/objects/pack/multi-pack-index")));
+       cl_git_pass(git_futils_readbuffer(&midx, git_buf_cstr(&midx_path)));
+       cl_assert_equal_i(git_buf_len(&midx), git_buf_len(&expected_midx));
+       cl_assert_equal_strn(git_buf_cstr(&midx), git_buf_cstr(&expected_midx), git_buf_len(&midx));
+
+       git_repository_free(repo);
+       git_buf_dispose(&midx);
+       git_buf_dispose(&midx_path);
+       git_buf_dispose(&expected_midx);
+
+       cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES));
+}
\ No newline at end of file
diff --git a/tests/pack/threadsafety.c b/tests/pack/threadsafety.c
new file mode 100644 (file)
index 0000000..fd6a61f
--- /dev/null
@@ -0,0 +1,62 @@
+#include "clar_libgit2.h"
+#include "pool.h"
+
+#include <git2.h>
+#include "git2/sys/commit.h"
+#include "git2/sys/mempack.h"
+
+static size_t original_mwindow_file_limit = 0;
+
+void test_pack_threadsafety__initialize(void)
+{
+       size_t open_mwindow_files = 1;
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, &original_mwindow_file_limit));
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, open_mwindow_files));
+}
+
+void test_pack_threadsafety__cleanup(void)
+{
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, original_mwindow_file_limit));
+}
+
+#ifdef GIT_THREADS
+static void *get_status(void *arg)
+{
+       const char *repo_path = (const char *)arg;
+       git_repository *repo;
+       git_status_list *status;
+
+       cl_git_pass(git_repository_open(&repo, repo_path));
+       cl_git_pass(git_status_list_new(&status, repo, NULL));
+       git_status_list_free(status);
+       git_repository_free(repo);
+
+       return NULL;
+}
+#endif
+
+void test_pack_threadsafety__open_repo_in_multiple_threads(void)
+{
+#ifdef GIT_THREADS
+       const char *repo_path = cl_fixture("../..");
+       git_repository *repo;
+       git_thread threads[8];
+       size_t i;
+
+       /* If we can't open the libgit2 repo or if it isn't a full repo
+        * with proper history, just skip this test */
+       if (git_repository_open(&repo, repo_path) < 0)
+               cl_skip();
+       if (git_repository_is_shallow(repo))
+               cl_skip();
+       git_repository_free(repo);
+
+       for (i = 0; i < ARRAY_SIZE(threads); i++)
+               git_thread_create(&threads[i], get_status, (void *)repo_path);
+       for (i = 0; i < ARRAY_SIZE(threads); i++)
+               git_thread_join(&threads[i], NULL);
+#else
+       cl_skip();
+#endif
+}
index 48b518c8d4c81825d00a8117c4bccdb11737796c..c875a862ce7b059bfb3ac274687652862967e36c 100644 (file)
@@ -1,6 +1,11 @@
 #include "clar_libgit2.h"
 #include "path.h"
 
+void test_path_core__cleanup(void)
+{
+       cl_git_sandbox_cleanup();
+}
+
 static void test_make_relative(
        const char *expected_path,
        const char *path,
@@ -44,266 +49,322 @@ void test_path_core__make_relative(void)
 
        test_make_relative("/path/to/foo.c", "/path/to/foo.c", "d:/path/to", GIT_ENOTFOUND);
        test_make_relative("d:/path/to/foo.c", "d:/path/to/foo.c", "/path/to", GIT_ENOTFOUND);
-       
+
        test_make_relative("/path/to/foo.c", "/path/to/foo.c", "not-a-rooted-path", GIT_ENOTFOUND);
        test_make_relative("not-a-rooted-path", "not-a-rooted-path", "/path/to", GIT_ENOTFOUND);
-       
+
        test_make_relative("/path", "/path", "pathtofoo", GIT_ENOTFOUND);
        test_make_relative("path", "path", "pathtofoo", GIT_ENOTFOUND);
 }
 
 void test_path_core__isvalid_standard(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar/file.txt", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar/.file", 0, 0));
 }
 
 void test_path_core__isvalid_empty_dir_component(void)
 {
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo//bar", 0, 0));
 
        /* leading slash */
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0, 0));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0, 0));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "/", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "/foo", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "/foo/bar", 0, 0));
 
        /* trailing slash */
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0, 0));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/", 0, 0));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar/", 0, 0));
 }
 
 void test_path_core__isvalid_dot_and_dotdot(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "..", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", 0, GIT_PATH_REJECT_TRAVERSAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "./foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "./foo", 0, 0));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, "..", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "../foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/..", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "../foo", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, ".", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/.", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "..", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/..", 0, GIT_PATH_REJECT_TRAVERSAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL));
 }
 
 void test_path_core__isvalid_dot_git(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git/foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/.git", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/.git/bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/.GIT/bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar/.Git", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git/foo", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/.git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/.git/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/.GIT/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar/.Git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, "!git", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/!git", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "!git/bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".tig", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/.tig", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".tig/bar", 0, 0));
 }
 
 void test_path_core__isvalid_backslash(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo\\file.txt", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar\\file.txt", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar\\", 0, 0));
 
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", 0, GIT_PATH_REJECT_BACKSLASH));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar\\", 0, GIT_PATH_REJECT_BACKSLASH));
 }
 
 void test_path_core__isvalid_trailing_dot(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", 0, GIT_PATH_REJECT_TRAILING_DOT));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", 0, GIT_PATH_REJECT_TRAILING_DOT));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", 0, GIT_PATH_REJECT_TRAILING_DOT));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", 0, GIT_PATH_REJECT_TRAILING_DOT));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo...", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo./bar", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo.", 0, GIT_PATH_REJECT_TRAILING_DOT));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo...", 0, GIT_PATH_REJECT_TRAILING_DOT));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar.", 0, GIT_PATH_REJECT_TRAILING_DOT));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo./bar", 0, GIT_PATH_REJECT_TRAILING_DOT));
 }
 
 void test_path_core__isvalid_trailing_space(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo   ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo   ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, " ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", 0, GIT_PATH_REJECT_TRAILING_SPACE));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo   ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, " ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo /bar", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo   ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
+       cl_assert_equal_b(false, git_path_validate(NULL, " ", 0, GIT_PATH_REJECT_TRAILING_SPACE));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo /bar", 0, GIT_PATH_REJECT_TRAILING_SPACE));
 }
 
 void test_path_core__isvalid_trailing_colon(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", 0, GIT_PATH_REJECT_TRAILING_COLON));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", 0, GIT_PATH_REJECT_TRAILING_COLON));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ":", 0, GIT_PATH_REJECT_TRAILING_COLON));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", 0, GIT_PATH_REJECT_TRAILING_COLON));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo:", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo/bar:", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ":", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "foo:/bar", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo:", 0, GIT_PATH_REJECT_TRAILING_COLON));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo/bar:", 0, GIT_PATH_REJECT_TRAILING_COLON));
+       cl_assert_equal_b(false, git_path_validate(NULL, ":", 0, GIT_PATH_REJECT_TRAILING_COLON));
+       cl_assert_equal_b(false, git_path_validate(NULL, "foo:/bar", 0, GIT_PATH_REJECT_TRAILING_COLON));
 }
 
 void test_path_core__isvalid_dotgit_ntfs(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0, 0));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git.. .", 0, 0));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, "git~1", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "git~1 ", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "git~1.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "git~1.. .", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "git~1", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "git~1 ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "git~1.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "git~1.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
 }
 
 void test_path_core__isvalid_dos_paths(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "con", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "prn", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", 0, GIT_PATH_REJECT_DOS_PATHS));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux:", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux.asdf", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux.asdf\\zippy", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux:asdf\\foobar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "con", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "prn", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "nul", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux.", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux:", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux.asdf", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "aux:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "con", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "prn", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "nul", 0, GIT_PATH_REJECT_DOS_PATHS));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux1", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux1", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "auxn", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "aux\\foo", 0, GIT_PATH_REJECT_DOS_PATHS));
 }
 
 void test_path_core__isvalid_dos_paths_withnum(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "com1/foo", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", 0, GIT_PATH_REJECT_DOS_PATHS));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt0", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt10", 0, GIT_PATH_REJECT_DOS_PATHS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "lptn", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1.", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1:", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1.asdf", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1.asdf\\zippy", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1:asdf\\foobar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1\\foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "lpt1", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1.", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1:", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1.asdf", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "com1/foo", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "lpt1", 0, GIT_PATH_REJECT_DOS_PATHS));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, "com0", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com0", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com10", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com10", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "comn", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "com1\\foo", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "lpt0", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "lpt10", 0, GIT_PATH_REJECT_DOS_PATHS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "lptn", 0, GIT_PATH_REJECT_DOS_PATHS));
 }
 
 void test_path_core__isvalid_nt_chars(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf<bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf>foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0, 0));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0, 0));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf<bar", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf>foo", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", 0, GIT_PATH_REJECT_NT_CHARS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf\001foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf\037bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf<bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf>foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf:foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf\"bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf|foo", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf?bar", 0, 0));
+       cl_assert_equal_b(true, git_path_validate(NULL, "asdf*bar", 0, 0));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf\001foo", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf\037bar", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf<bar", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf>foo", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf:foo", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf\"bar", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf|foo", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf?bar", 0, GIT_PATH_REJECT_NT_CHARS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "asdf*bar", 0, GIT_PATH_REJECT_NT_CHARS));
 }
 
 void test_path_core__isvalid_dotgit_with_hfs_ignorables(void)
 {
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".g\xe2\x80\x8eIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".\xe2\x80\x8fgIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xaa.gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".g", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, " .git", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "..git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT.", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2\x80It", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".\xe2gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, "\xe2\x80\xaa.gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2i\x80T\x8e", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".gi\xe2\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".g\xe2\x80\x8eIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".\xe2\x80\x8fgIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "\xe2\x80\xaa.gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+
+       cl_assert_equal_b(false, git_path_validate(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+
+       cl_assert_equal_b(true, git_path_validate(NULL, ".", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".g", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, " .git", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "..git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".gi\xe2\x80\x8dT.", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".g\xe2\x80It", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".\xe2gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, "\xe2\x80\xaa.gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".gi\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".gi\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".g\xe2i\x80T\x8e", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git\xe2\x80\xbf", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".git\xe2\xab\x81", 0, GIT_PATH_REJECT_DOT_GIT_HFS));
+}
+
+void test_path_core__validate_workdir(void)
+{
+       cl_must_pass(git_path_validate_workdir(NULL, "/foo/bar"));
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\Foo\\Bar"));
+       cl_must_pass(git_path_validate_workdir(NULL, "\\\\?\\C:\\Foo\\Bar"));
+       cl_must_pass(git_path_validate_workdir(NULL, "\\\\?\\C:\\Foo\\Bar"));
+       cl_must_pass(git_path_validate_workdir(NULL, "\\\\?\\UNC\\server\\C$\\folder"));
+
+#ifdef GIT_WIN32
+       /*
+        * In the absense of a repo configuration, 259 character paths
+        * succeed. >= 260 character paths fail.
+        */
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\ok.txt"));
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\260.txt"));
+       cl_must_fail(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\longer_than_260.txt"));
+
+       /* count characters, not bytes */
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\\260.txt"));
+       cl_must_fail(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\\long.txt"));
+#else
+       cl_must_pass(git_path_validate_workdir(NULL, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/ok.txt"));
+       cl_must_pass(git_path_validate_workdir(NULL, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/260.txt"));
+       cl_must_pass(git_path_validate_workdir(NULL, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/longer_than_260.txt"));
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\\260.txt"));
+       cl_must_pass(git_path_validate_workdir(NULL, "C:\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\aaaaaaaaa\\\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\xc2\xa2\\long.txt"));
+#endif
+}
+
+void test_path_core__validate_workdir_with_core_longpath(void)
+{
+#ifdef GIT_WIN32
+       git_repository *repo;
+       git_config *config;
+
+       repo = cl_git_sandbox_init("empty_bare.git");
+
+       cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+       cl_git_pass(git_repository_config(&config, repo));
+
+       /* fail by default */
+       cl_must_fail(git_path_validate_workdir(repo, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/longer_than_260.txt"));
+
+       /* set core.longpaths explicitly on */
+       cl_git_pass(git_config_set_bool(config, "core.longpaths", 1));
+       cl_must_pass(git_path_validate_workdir(repo, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/longer_than_260.txt"));
+
+       /* set core.longpaths explicitly off */
+       cl_git_pass(git_config_set_bool(config, "core.longpaths", 0));
+       cl_must_fail(git_path_validate_workdir(repo, "/c/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/aaaaaaaaa/longer_than_260.txt"));
+
+       git_config_free(config);
+       git_repository_free(repo);
+#endif
 }
 
 static void test_join_unrooted(
index ceb7330d248edf6c0bc955feaa1db0c70140b321..2f9fcae4fc8e7a9786847ba81e9f3925c504b904 100644 (file)
@@ -113,8 +113,8 @@ void test_path_dotgit__dotgit_modules(void)
 
 void test_path_dotgit__dotgit_modules_symlink(void)
 {
-       cl_assert_equal_b(true, git_path_isvalid(NULL, ".gitmodules", 0, GIT_PATH_REJECT_DOT_GIT_HFS|GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_HFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS));
-       cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules . .::$DATA", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(true, git_path_validate(NULL, ".gitmodules", 0, GIT_PATH_REJECT_DOT_GIT_HFS|GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_HFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS));
+       cl_assert_equal_b(false, git_path_validate(NULL, ".gitmodules . .::$DATA", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS));
 }
index b416e9e60263f0e5cfdb47b8374efa0bf2839022..46b5c9f7015326465ea64e894af5f5634b488f31 100644 (file)
@@ -78,13 +78,11 @@ void test_path_win32__honors_max_path(void)
 #ifdef GIT_WIN32
        git_win32_path path_utf16;
 
-       test_utf8_to_utf16("C:\\This path is 259 chars and is the max length in windows\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij",
-               L"\\\\?\\C:\\This path is 259 chars and is the max length in windows\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij");
-       test_utf8_to_utf16("\\\\unc\\paths may also be 259 characters including the server\\123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij",
-               L"\\\\?\\UNC\\unc\\paths may also be 259 characters including the server\\123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij");
+       test_utf8_to_utf16("C:\\This path is 261 characters which is fine for our path handling functions which cope with paths longer than MAX_PATH\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghijk",
+               L"\\\\?\\C:\\This path is 261 characters which is fine for our path handling functions which cope with paths longer than MAX_PATH\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghijk");
+
+       cl_check_fail(git_win32_path_from_utf8(path_utf16, "C:\\This path is 4097 chars and exceeds our maximum path length on Windows which is limited to 4096 characters\\alas\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij01"));
 
-       cl_check_fail(git_win32_path_from_utf8(path_utf16, "C:\\This path is 260 chars and is sadly too long for windows\\0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij"));
-       cl_check_fail(git_win32_path_from_utf8(path_utf16, "\\\\unc\\paths are also bound by 260 character restrictions\\including the server name portion\\bcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij"));
 #endif
 }
 
index fa47766618813122738d02db8feaa35de49d864e..06c18937aa19c25ebdfd944029412f002f2aeff0 100644 (file)
@@ -18,7 +18,239 @@ void test_rebase_sign__cleanup(void)
        cl_git_sandbox_cleanup();
 }
 
-static const char *expected_commit_content = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+static int create_cb_passthrough(
+       git_oid *out,
+       const git_signature *author,
+       const git_signature *committer,
+       const char *message_encoding,
+       const char *message,
+       const git_tree *tree,
+       size_t parent_count,
+       const git_commit *parents[],
+       void *payload)
+{
+       GIT_UNUSED(out);
+       GIT_UNUSED(author);
+       GIT_UNUSED(committer);
+       GIT_UNUSED(message_encoding);
+       GIT_UNUSED(message);
+       GIT_UNUSED(tree);
+       GIT_UNUSED(parent_count);
+       GIT_UNUSED(parents);
+       GIT_UNUSED(payload);
+
+       return GIT_PASSTHROUGH;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__passthrough_create_cb(void)
+{
+       git_rebase *rebase;
+       git_reference *branch_ref, *upstream_ref;
+       git_annotated_commit *branch_head, *upstream_head;
+       git_rebase_operation *rebase_operation;
+       git_oid commit_id, expected_id;
+       git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+       git_commit *commit;
+       const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n";
+
+       rebase_opts.commit_create_cb = create_cb_passthrough;
+
+       cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+       cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+       cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+       cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+       cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+       cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+       cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+       git_oid_fromstr(&expected_id, "129183968a65abd6c52da35bff43325001bfc630");
+       cl_assert_equal_oid(&expected_id, &commit_id);
+
+       cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+       cl_assert_equal_s(expected_commit_raw_header, git_commit_raw_header(commit));
+
+       cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase));
+
+       git_reference_free(branch_ref);
+       git_reference_free(upstream_ref);
+       git_annotated_commit_free(branch_head);
+       git_annotated_commit_free(upstream_head);
+       git_commit_free(commit);
+       git_rebase_free(rebase);
+}
+
+int create_cb_signed_gpg(
+       git_oid *out,
+       const git_signature *author,
+       const git_signature *committer,
+       const char *message_encoding,
+       const char *message,
+       const git_tree *tree,
+       size_t parent_count,
+       const git_commit *parents[],
+       void *payload)
+{
+       git_buf commit_content = GIT_BUF_INIT;
+       const char *gpg_signature = "-----BEGIN PGP SIGNATURE-----\n\
+\n\
+iQIzBAEBCgAdFiEEgVlDEfSlmKn0fvGgK++h5T2/ctIFAlwZcrAACgkQK++h5T2/\n\
+ctIPVhAA42RyZhMdKl5Bm0KtQco2scsukIg2y7tjSwhti91zDu3HQgpusjjo0fQx\n\
+ZzB+OrmlvQ9CDcGpZ0THIzXD8GRJoDMPqdrvZVrBWkGcHvw7/YPA8skzsjkauJ8W\n\
+7lzF5LCuHSS6OUmPT/+5hEHPin5PB3zhfszyC+Q7aujnIuPJMrKiMnUa+w1HWifM\n\
+km49OOygQ9S6NQoVuEQede22+c76DlDL7yFghGoo1f0sKCE/9LW6SEnwI/bWv9eo\n\
+nom5vOPrvQeJiYCQk+2DyWo8RdSxINtY+G9bPE4RXm+6ZgcXECPm9TYDIWpL36fC\n\
+jvtGLs98woWFElOziBMp5Tb630GMcSI+q5ivHfJ3WS5NKLYLHBNK4iSFN0/dgAnB\n\
+dj6GcKXKWnIBWn6ZM4o40pcM5KSRUUCLtA0ZmjJH4c4zx3X5fUxd+enwkf3e9VZO\n\
+fNKC/+xfq6NfoPUPK9+UnchHpJaJw7RG5tZS+sWCz2xpQ1y3/o49xImNyM3wnpvB\n\
+cRAZabqIHpZa9/DIUkELOtCzln6niqkjRgg3M/YCCNznwV+0RNgz87VtyTPerdef\n\
+xrqn0+ROMF6ebVqIs6PPtuPkxnAJu7TMKXVB5rFnAewS24e6cIGFzeIA7810py3l\n\
+cttVRsdOoego+fiy08eFE+aJIeYiINRGhqOBTsuqG4jIdpdKxPE=\n\
+=KbsY\n\
+-----END PGP SIGNATURE-----";
+
+       git_repository *repo = (git_repository *)payload;
+       int error;
+
+       if ((error = git_commit_create_buffer(&commit_content,
+               repo, author, committer, message_encoding, message,
+               tree, parent_count, parents)) < 0)
+               goto done;
+
+       error = git_commit_create_with_signature(out, repo,
+               commit_content.ptr,
+               gpg_signature,
+               NULL);
+
+done:
+       git_buf_dispose(&commit_content);
+       return error;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__create_gpg_signed(void)
+{
+       git_rebase *rebase;
+       git_reference *branch_ref, *upstream_ref;
+       git_annotated_commit *branch_head, *upstream_head;
+       git_rebase_operation *rebase_operation;
+       git_oid commit_id, expected_id;
+       git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+       git_commit *commit;
+       const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
+gpgsig -----BEGIN PGP SIGNATURE-----\n\
+ \n\
+ iQIzBAEBCgAdFiEEgVlDEfSlmKn0fvGgK++h5T2/ctIFAlwZcrAACgkQK++h5T2/\n\
+ ctIPVhAA42RyZhMdKl5Bm0KtQco2scsukIg2y7tjSwhti91zDu3HQgpusjjo0fQx\n\
+ ZzB+OrmlvQ9CDcGpZ0THIzXD8GRJoDMPqdrvZVrBWkGcHvw7/YPA8skzsjkauJ8W\n\
+ 7lzF5LCuHSS6OUmPT/+5hEHPin5PB3zhfszyC+Q7aujnIuPJMrKiMnUa+w1HWifM\n\
+ km49OOygQ9S6NQoVuEQede22+c76DlDL7yFghGoo1f0sKCE/9LW6SEnwI/bWv9eo\n\
+ nom5vOPrvQeJiYCQk+2DyWo8RdSxINtY+G9bPE4RXm+6ZgcXECPm9TYDIWpL36fC\n\
+ jvtGLs98woWFElOziBMp5Tb630GMcSI+q5ivHfJ3WS5NKLYLHBNK4iSFN0/dgAnB\n\
+ dj6GcKXKWnIBWn6ZM4o40pcM5KSRUUCLtA0ZmjJH4c4zx3X5fUxd+enwkf3e9VZO\n\
+ fNKC/+xfq6NfoPUPK9+UnchHpJaJw7RG5tZS+sWCz2xpQ1y3/o49xImNyM3wnpvB\n\
+ cRAZabqIHpZa9/DIUkELOtCzln6niqkjRgg3M/YCCNznwV+0RNgz87VtyTPerdef\n\
+ xrqn0+ROMF6ebVqIs6PPtuPkxnAJu7TMKXVB5rFnAewS24e6cIGFzeIA7810py3l\n\
+ cttVRsdOoego+fiy08eFE+aJIeYiINRGhqOBTsuqG4jIdpdKxPE=\n\
+ =KbsY\n\
+ -----END PGP SIGNATURE-----\n";
+
+       rebase_opts.commit_create_cb = create_cb_signed_gpg;
+       rebase_opts.payload = repo;
+
+       cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+       cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+       cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+       cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+       cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+       cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+       cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+       git_oid_fromstr(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef");
+       cl_assert_equal_oid(&expected_id, &commit_id);
+
+       cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+       cl_assert_equal_s(expected_commit_raw_header, git_commit_raw_header(commit));
+
+       cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase));
+
+       git_reference_free(branch_ref);
+       git_reference_free(upstream_ref);
+       git_annotated_commit_free(branch_head);
+       git_annotated_commit_free(upstream_head);
+       git_commit_free(commit);
+       git_rebase_free(rebase);
+}
+
+static int create_cb_error(
+       git_oid *out,
+       const git_signature *author,
+       const git_signature *committer,
+       const char *message_encoding,
+       const char *message,
+       const git_tree *tree,
+       size_t parent_count,
+       const git_commit *parents[],
+       void *payload)
+{
+       GIT_UNUSED(out);
+       GIT_UNUSED(author);
+       GIT_UNUSED(committer);
+       GIT_UNUSED(message_encoding);
+       GIT_UNUSED(message);
+       GIT_UNUSED(tree);
+       GIT_UNUSED(parent_count);
+       GIT_UNUSED(parents);
+       GIT_UNUSED(payload);
+
+       return GIT_EUSER;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__create_propagates_error(void)
+{
+       git_rebase *rebase;
+       git_reference *branch_ref, *upstream_ref;
+       git_annotated_commit *branch_head, *upstream_head;
+       git_oid commit_id;
+       git_rebase_operation *rebase_operation;
+       git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+
+       rebase_opts.commit_create_cb = create_cb_error;
+
+       cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+       cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+       cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+       cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+       cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+       cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+       cl_git_fail_with(GIT_EUSER, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+       git_reference_free(branch_ref);
+       git_reference_free(upstream_ref);
+       git_annotated_commit_free(branch_head);
+       git_annotated_commit_free(upstream_head);
+       git_rebase_free(rebase);
+}
+
+#ifndef GIT_DEPRECATE_HARD
+static const char *expected_commit_content = "\
+tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
 parent f87d14a4a236582a0278a916340a793714256864\n\
 author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
 committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
@@ -37,10 +269,12 @@ int signing_cb_passthrough(
        cl_assert_equal_p(NULL, payload);
        return GIT_PASSTHROUGH;
 }
+#endif /* !GIT_DEPRECATE_HARD */
 
 /* git checkout gravy ; git rebase --merge veal */
 void test_rebase_sign__passthrough_signing_cb(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_rebase *rebase;
        git_reference *branch_ref, *upstream_ref;
        git_annotated_commit *branch_head, *upstream_head;
@@ -80,15 +314,18 @@ committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n";
        git_annotated_commit_free(upstream_head);
        git_commit_free(commit);
        git_rebase_free(rebase);
+#endif /* !GIT_DEPRECATE_HARD */
 }
 
+#ifndef GIT_DEPRECATE_HARD
 int signing_cb_gpg(
        git_buf *signature,
        git_buf *signature_field,
        const char *commit_content,
        void *payload)
 {
-       const char *gpg_signature = "-----BEGIN PGP SIGNATURE-----\n\
+       const char *gpg_signature = "\
+-----BEGIN PGP SIGNATURE-----\n\
 \n\
 iQIzBAEBCgAdFiEEgVlDEfSlmKn0fvGgK++h5T2/ctIFAlwZcrAACgkQK++h5T2/\n\
 ctIPVhAA42RyZhMdKl5Bm0KtQco2scsukIg2y7tjSwhti91zDu3HQgpusjjo0fQx\n\
@@ -113,10 +350,12 @@ cttVRsdOoego+fiy08eFE+aJIeYiINRGhqOBTsuqG4jIdpdKxPE=\n\
        cl_git_pass(git_buf_set(signature, gpg_signature, strlen(gpg_signature) + 1));
        return GIT_OK;
 }
+#endif /* !GIT_DEPRECATE_HARD */
 
 /* git checkout gravy ; git rebase --merge veal */
 void test_rebase_sign__gpg_with_no_field(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_rebase *rebase;
        git_reference *branch_ref, *upstream_ref;
        git_annotated_commit *branch_head, *upstream_head;
@@ -124,7 +363,8 @@ void test_rebase_sign__gpg_with_no_field(void)
        git_oid commit_id, expected_id;
        git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
        git_commit *commit;
-       const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+       const char *expected_commit_raw_header = "\
+tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
 parent f87d14a4a236582a0278a916340a793714256864\n\
 author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
 committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
@@ -172,9 +412,11 @@ gpgsig -----BEGIN PGP SIGNATURE-----\n\
        git_annotated_commit_free(upstream_head);
        git_commit_free(commit);
        git_rebase_free(rebase);
+#endif /* !GIT_DEPRECATE_HARD */
 }
 
 
+#ifndef GIT_DEPRECATE_HARD
 int signing_cb_magic_field(
        git_buf *signature,
        git_buf *signature_field,
@@ -196,10 +438,12 @@ int signing_cb_magic_field(
 
        return GIT_OK;
 }
+#endif /* !GIT_DEPRECATE_HARD */
 
 /* git checkout gravy ; git rebase --merge veal */
 void test_rebase_sign__custom_signature_field(void)
 {
+#ifndef GIT_DEPRECATE_HARD
        git_rebase *rebase;
        git_reference *branch_ref, *upstream_ref;
        git_annotated_commit *branch_head, *upstream_head;
@@ -207,7 +451,8 @@ void test_rebase_sign__custom_signature_field(void)
        git_oid commit_id, expected_id;
        git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
        git_commit *commit;
-       const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+       const char *expected_commit_raw_header = "\
+tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
 parent f87d14a4a236582a0278a916340a793714256864\n\
 author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
 committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
@@ -240,4 +485,5 @@ magicsig magic word: pretty please\n";
        git_annotated_commit_free(upstream_head);
        git_commit_free(commit);
        git_rebase_free(rebase);
+#endif /* !GIT_DEPRECATE_HARD */
 }
index ed0c0bde6bc817fcb31384b4373ae2e39954feb8..9e4c229648489974dd5128a94d8b04218c55bc51 100644 (file)
@@ -42,3 +42,44 @@ void test_refs_basic__reference_realloc(void)
        git_reference_free(new_ref);
        git_reference_free(ref);
 }
+
+void test_refs_basic__longpaths(void)
+{
+#ifdef GIT_WIN32
+       const char *base;
+       size_t base_len, extra_len;
+       ssize_t remain_len, i;
+       git_buf refname = GIT_BUF_INIT;
+       git_reference *one = NULL, *two = NULL;
+       git_oid id;
+
+       cl_git_pass(git_oid_fromstr(&id, "099fabac3a9ea935598528c27f866e34089c2eff"));
+
+       base = git_repository_path(g_repo);
+       base_len = git_utf8_char_length(base, strlen(base));
+       extra_len = CONST_STRLEN("logs/refs/heads/") + CONST_STRLEN(".lock");
+
+       remain_len = (ssize_t)MAX_PATH - (base_len + extra_len);
+       cl_assert(remain_len > 0);
+
+       cl_git_pass(git_buf_puts(&refname, "refs/heads/"));
+
+       for (i = 0; i < remain_len; i++) {
+               cl_git_pass(git_buf_putc(&refname, 'a'));
+       }
+
+       /*
+        * The full path to the reflog lockfile is 260 characters,
+        * this is permitted.
+        */
+       cl_git_pass(git_reference_create(&one, g_repo, refname.ptr, &id, 0, NULL));
+
+       /* Adding one more character gives us a path that is too long. */
+       cl_git_pass(git_buf_putc(&refname, 'z'));
+       cl_git_fail(git_reference_create(&two, g_repo, refname.ptr, &id, 0, NULL));
+
+       git_reference_free(one);
+       git_reference_free(two);
+       git_buf_dispose(&refname);
+#endif
+}
index 176f836a426e2c590b6390c585b59241237339c4..290916eecd0d5fad3e3e9f0a50e17ff3ff2da508 100644 (file)
@@ -43,3 +43,20 @@ void test_refs_branches_name__error_when_ref_is_no_branch(void)
        cl_git_pass(git_reference_lookup(&ref,repo,"refs/notes/fanout"));
        cl_git_fail(git_branch_name(&name,ref));
 }
+
+static int name_is_valid(const char *name)
+{
+       int valid;
+       cl_git_pass(git_branch_name_is_valid(&valid, name));
+       return valid;
+}
+
+void test_refs_branches_is_name_valid(void)
+{
+       cl_assert_equal_i(true, name_is_valid("master"));
+       cl_assert_equal_i(true, name_is_valid("test/master"));
+
+       cl_assert_equal_i(false, name_is_valid(""));
+       cl_assert_equal_i(false, name_is_valid("HEAD"));
+       cl_assert_equal_i(false, name_is_valid("-dash"));
+}
index 928a9ff7bee19ce38bfad67474edcad4a448530b..919705e07b402db3f31ad50dd237e7f744b297c1 100644 (file)
@@ -71,6 +71,31 @@ void test_refs_branches_upstream__upstream_remote(void)
        git_buf_dispose(&buf);
 }
 
+void test_refs_branches_upstream__upstream_merge(void)
+{
+       git_reference *branch;
+       git_repository *repository;
+       git_buf buf = GIT_BUF_INIT;
+
+       repository = cl_git_sandbox_init("testrepo.git");
+
+       /* check repository */
+       cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test"));
+       cl_git_pass(git_branch_set_upstream(branch, "test/master"));
+
+       assert_config_entry_value(repository, "branch.test.remote", "test");
+       assert_config_entry_value(repository, "branch.test.merge", "refs/heads/master");
+
+       git_reference_free(branch);
+
+       /* check merge branch */
+       cl_git_pass(git_branch_upstream_merge(&buf, repository, "refs/heads/test"));
+       cl_assert_equal_s("refs/heads/master", buf.ptr);
+       git_buf_dispose(&buf);
+
+       cl_git_sandbox_cleanup();
+}
+
 void test_refs_branches_upstream__upstream_remote_empty_value(void)
 {
        git_repository *repository;
index 65c70ba4d88eefb0f62f4a634dea27548d54a758..063f0f798f9c5213546bbac7e8507524747b58f7 100644 (file)
@@ -1,31 +1,38 @@
 #include "clar_libgit2.h"
 
+static bool is_valid_name(const char *name)
+{
+       int valid;
+       cl_git_pass(git_reference_name_is_valid(&valid, name));
+       return valid;
+}
+
 void test_refs_isvalidname__can_detect_invalid_formats(void)
 {
-       cl_assert_equal_i(false, git_reference_is_valid_name("refs/tags/0.17.0^{}"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("TWO/LEVELS"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("ONE.LEVEL"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("NO_TRAILING_UNDERSCORE_"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("_NO_LEADING_UNDERSCORE"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/aa"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("lower_case"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("/stupid/name/master"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("/"));
-       cl_assert_equal_i(false, git_reference_is_valid_name("//"));
-       cl_assert_equal_i(false, git_reference_is_valid_name(""));
-       cl_assert_equal_i(false, git_reference_is_valid_name("refs/heads/sub.lock/webmatrix"));
+       cl_assert_equal_i(false, is_valid_name("refs/tags/0.17.0^{}"));
+       cl_assert_equal_i(false, is_valid_name("TWO/LEVELS"));
+       cl_assert_equal_i(false, is_valid_name("ONE.LEVEL"));
+       cl_assert_equal_i(false, is_valid_name("HEAD/"));
+       cl_assert_equal_i(false, is_valid_name("NO_TRAILING_UNDERSCORE_"));
+       cl_assert_equal_i(false, is_valid_name("_NO_LEADING_UNDERSCORE"));
+       cl_assert_equal_i(false, is_valid_name("HEAD/aa"));
+       cl_assert_equal_i(false, is_valid_name("lower_case"));
+       cl_assert_equal_i(false, is_valid_name("/stupid/name/master"));
+       cl_assert_equal_i(false, is_valid_name("/"));
+       cl_assert_equal_i(false, is_valid_name("//"));
+       cl_assert_equal_i(false, is_valid_name(""));
+       cl_assert_equal_i(false, is_valid_name("refs/heads/sub.lock/webmatrix"));
 }
 
 void test_refs_isvalidname__wont_hopefully_choke_on_valid_formats(void)
 {
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/tags/0.17.0"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/LEVELS"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("HEAD"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("ONE_LEVEL"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/stash"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/remotes/origin/bim_with_3d@11296"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/master}yesterday"));
-       cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday}"));
+       cl_assert_equal_i(true, is_valid_name("refs/tags/0.17.0"));
+       cl_assert_equal_i(true, is_valid_name("refs/LEVELS"));
+       cl_assert_equal_i(true, is_valid_name("HEAD"));
+       cl_assert_equal_i(true, is_valid_name("ONE_LEVEL"));
+       cl_assert_equal_i(true, is_valid_name("refs/stash"));
+       cl_assert_equal_i(true, is_valid_name("refs/remotes/origin/bim_with_3d@11296"));
+       cl_assert_equal_i(true, is_valid_name("refs/master{yesterday"));
+       cl_assert_equal_i(true, is_valid_name("refs/master}yesterday"));
+       cl_assert_equal_i(true, is_valid_name("refs/master{yesterday}"));
 }
index 04a1bc17b3b97f8f302efe46d53ca9c2c2652bad..476789358d698d9c1075143eb4c7e808cb1c6ad7 100644 (file)
@@ -22,6 +22,24 @@ void test_refs_races__cleanup(void)
    cl_git_sandbox_cleanup();
 }
 
+void test_refs_races__create_matching_zero_old(void)
+{
+       git_reference *ref;
+       git_oid id, zero_id;
+
+       git_oid_fromstr(&id, commit_id);
+       git_oid_fromstr(&zero_id, "0000000000000000000000000000000000000000");
+
+       cl_git_fail(git_reference_create_matching(&ref, g_repo, refname, &id, 1, &zero_id, NULL));
+       git_reference_free(ref);
+
+       cl_git_pass(git_reference_create_matching(&ref, g_repo, other_refname, &id, 1, &zero_id, NULL));
+       git_reference_free(ref);
+
+       cl_git_fail(git_reference_create_matching(&ref, g_repo, other_refname, &id, 1, &zero_id, NULL));
+       git_reference_free(ref);
+}
+
 void test_refs_races__create_matching(void)
 {
        git_reference *ref, *ref2, *ref3;
index 3c4ed9af5bfb0ea7c030e033ad292d907eb87adf..bc6e0a4c4115114f93a759ee11f17bb231620e39 100644 (file)
@@ -50,7 +50,7 @@ static void test_id_inrepo(
        const char *spec,
        const char *expected_left,
        const char *expected_right,
-       git_revparse_mode_t expected_flags,
+       git_revspec_t expected_flags,
        git_repository *repo)
 {
        git_revspec revspec;
@@ -90,7 +90,7 @@ static void test_object_and_ref(const char *spec, const char *expected_oid, cons
 static void test_rangelike(const char *rangelike,
                                                   const char *expected_left,
                                                   const char *expected_right,
-                                                  git_revparse_mode_t expected_revparseflags)
+                                                  git_revspec_t expected_revparseflags)
 {
        char objstr[64] = {0};
        git_revspec revspec;
@@ -117,7 +117,7 @@ static void test_id(
        const char *spec,
        const char *expected_left,
        const char *expected_right,
-       git_revparse_mode_t expected_flags)
+       git_revspec_t expected_flags)
 {
        test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo);
 }
@@ -735,53 +735,53 @@ void test_refs_revparse__range(void)
        test_rangelike("be3563a^1..be3563a",
                       "9fd738e8f7967c078dceed8190330fc8648ee56a",
                       "be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
-                      GIT_REVPARSE_RANGE);
+                      GIT_REVSPEC_RANGE);
 
        test_rangelike("be3563a^1...be3563a",
                       "9fd738e8f7967c078dceed8190330fc8648ee56a",
                       "be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
-                      GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+                      GIT_REVSPEC_RANGE | GIT_REVSPEC_MERGE_BASE);
 
        test_rangelike("be3563a^1.be3563a", NULL, NULL, 0);
 }
 
 void test_refs_revparse__parses_range_operator(void)
 {
-       test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE);
+       test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVSPEC_SINGLE);
        test_id("HEAD~3..HEAD",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
-               GIT_REVPARSE_RANGE);
+               GIT_REVSPEC_RANGE);
 
        test_id("HEAD~3...HEAD",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
-               GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+               GIT_REVSPEC_RANGE | GIT_REVSPEC_MERGE_BASE);
 
        test_id("HEAD~3..",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
-               GIT_REVPARSE_RANGE);
+               GIT_REVSPEC_RANGE);
 
        test_id("HEAD~3...",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
-               GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+               GIT_REVSPEC_RANGE | GIT_REVSPEC_MERGE_BASE);
 
        test_id("..HEAD~3",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
-               GIT_REVPARSE_RANGE);
+               GIT_REVSPEC_RANGE);
 
        test_id("...HEAD~3",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
                "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
-               GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+               GIT_REVSPEC_RANGE | GIT_REVSPEC_MERGE_BASE);
 
        test_id("...",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
                "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
-               GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+               GIT_REVSPEC_RANGE | GIT_REVSPEC_MERGE_BASE);
 
        test_invalid_revspec("..");
 }
diff --git a/tests/refs/tags/name.c b/tests/refs/tags/name.c
new file mode 100644 (file)
index 0000000..0ca5df7
--- /dev/null
@@ -0,0 +1,17 @@
+#include "clar_libgit2.h"
+
+static int name_is_valid(const char *name)
+{
+       int valid;
+       cl_git_pass(git_tag_name_is_valid(&valid, name));
+       return valid;
+}
+
+void test_refs_tags_is_name_valid(void)
+{
+       cl_assert_equal_i(true, name_is_valid("sometag"));
+       cl_assert_equal_i(true, name_is_valid("test/sometag"));
+
+       cl_assert_equal_i(false, name_is_valid(""));
+       cl_assert_equal_i(false, name_is_valid("-dash"));
+}
diff --git a/tests/remote/fetch.c b/tests/remote/fetch.c
new file mode 100644 (file)
index 0000000..7e825ca
--- /dev/null
@@ -0,0 +1,169 @@
+#include "../clar_libgit2.h"
+
+#include "remote.h"
+#include "repository.h"
+
+static git_repository *repo1;
+static git_repository *repo2;
+static char* repo1_path;
+static char* repo2_path;
+
+static const char *REPO1_REFNAME = "refs/heads/main";
+static const char *REPO2_REFNAME = "refs/remotes/repo1/main";
+static char *FORCE_FETCHSPEC = "+refs/heads/main:refs/remotes/repo1/main";
+static char *NON_FORCE_FETCHSPEC = "refs/heads/main:refs/remotes/repo1/main";
+
+void test_remote_fetch__initialize(void) {
+       git_config *c;
+       git_buf repo1_path_buf = GIT_BUF_INIT;
+       git_buf repo2_path_buf = GIT_BUF_INIT;
+       const char *sandbox = clar_sandbox_path();
+
+       cl_git_pass(git_buf_joinpath(&repo1_path_buf, sandbox, "fetchtest_repo1"));
+       repo1_path = git_buf_detach(&repo1_path_buf);
+       cl_git_pass(git_repository_init(&repo1, repo1_path, true));
+
+       cl_git_pass(git_buf_joinpath(&repo2_path_buf, sandbox, "fetchtest_repo2"));
+       repo2_path = git_buf_detach(&repo2_path_buf);
+       cl_git_pass(git_repository_init(&repo2, repo2_path, true));
+
+       cl_git_pass(git_repository_config(&c, repo1));
+       cl_git_pass(git_config_set_string(c, "user.email", "some@email"));
+       cl_git_pass(git_config_set_string(c, "user.name", "some@name"));
+       git_config_free(c);
+       git_buf_dispose(&repo1_path_buf);
+       git_buf_dispose(&repo2_path_buf);
+}
+
+void test_remote_fetch__cleanup(void) {
+       git_repository_free(repo1);
+       git_repository_free(repo2);
+
+       cl_git_pass(git_futils_rmdir_r(repo1_path, NULL, GIT_RMDIR_REMOVE_FILES));
+       free(repo1_path);
+
+       cl_git_pass(git_futils_rmdir_r(repo2_path, NULL, GIT_RMDIR_REMOVE_FILES));
+       free(repo2_path);
+}
+
+
+/**
+ * This checks that the '+' flag on fetchspecs is respected. We create a
+ * repository that has a reference to two commits, one a child of the other.
+ * We fetch this repository into a second repository. Then we reset the
+ * reference in the first repository and run the fetch again. If the '+' flag
+ * is used then the reference in the second repository will change, but if it
+ * is not then it should stay the same.
+ *
+ * @param commit1id A pointer to an OID which will be populated with the first
+ *                  commit.
+ * @param commit2id A pointer to an OID which will be populated with the second
+ *                  commit, which is a descendant of the first.
+ * @param force     Whether to use a spec with '+' prefixed to force the refs
+ *                  to update
+ */
+void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
+               bool force) {
+       char *refspec_strs = {
+               force ? FORCE_FETCHSPEC : NON_FORCE_FETCHSPEC,
+       };
+       git_strarray refspecs = {
+               .count = 1,
+               .strings = &refspec_strs,
+       };
+
+       /* create two commits in repo 1 and a reference to them */
+       {
+               git_oid empty_tree_id;
+               git_tree *empty_tree;
+               git_signature *sig;
+               git_treebuilder *tb;
+               cl_git_pass(git_treebuilder_new(&tb, repo1, NULL));
+               cl_git_pass(git_treebuilder_write(&empty_tree_id, tb));
+               cl_git_pass(git_tree_lookup(&empty_tree, repo1, &empty_tree_id));
+               cl_git_pass(git_signature_default(&sig, repo1));
+               cl_git_pass(git_commit_create(commit1id, repo1, REPO1_REFNAME, sig, 
+                                       sig, NULL, "one", empty_tree, 0, NULL));
+               cl_git_pass(git_commit_create_v(commit2id, repo1, REPO1_REFNAME, sig, 
+                                       sig, NULL, "two", empty_tree, 1, commit1id));
+
+               git_tree_free(empty_tree);
+               git_signature_free(sig);
+               git_treebuilder_free(tb);
+       }
+
+       /* fetch the reference via the remote */
+       {
+               git_remote *remote;
+
+               cl_git_pass(git_remote_create_anonymous(&remote, repo2,
+                                       git_repository_path(repo1)));
+               cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, "some message"));
+
+               git_remote_free(remote);
+       }
+
+       /* assert that repo2 references the second commit */
+       {
+               const git_oid *target;
+               git_reference *ref;
+               cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
+               target = git_reference_target(ref);
+               cl_assert_equal_b(git_oid_cmp(target, commit2id), 0);
+               git_reference_free(ref);
+       }
+
+       /* set the reference in repo1 to point to the older commit */
+       {
+               git_reference *ref;
+               git_reference *ref2;
+               cl_git_pass(git_reference_lookup(&ref, repo1, REPO1_REFNAME));
+               cl_git_pass(git_reference_set_target(&ref2, ref, commit1id, 
+                                       "rollback"));
+               git_reference_free(ref);
+               git_reference_free(ref2);
+       }
+
+       /* fetch the reference again */
+       {
+               git_remote *remote;
+
+               cl_git_pass(git_remote_create_anonymous(&remote, repo2,
+                                       git_repository_path(repo1)));
+               cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, "some message"));
+
+               git_remote_free(remote);
+       }
+}
+
+void test_remote_fetch__dont_update_refs_if_not_descendant_and_not_force(void) {
+       const git_oid *target;
+       git_oid commit1id;
+       git_oid commit2id;
+       git_reference *ref;
+
+       do_time_travelling_fetch(&commit1id, &commit2id, false);
+
+       /* assert that the reference in repo2 has not changed */
+       cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
+       target = git_reference_target(ref);
+       cl_assert_equal_b(git_oid_cmp(target, &commit2id), 0);
+
+       git_reference_free(ref);
+}
+
+void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) {
+       const git_oid *target;
+       git_oid commit1id;
+       git_oid commit2id;
+       git_reference *ref;
+
+       do_time_travelling_fetch(&commit1id, &commit2id, true);
+
+       /* assert that the reference in repo2 has changed */
+       cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
+       target = git_reference_target(ref);
+       cl_assert_equal_b(git_oid_cmp(target, &commit1id), 0);
+
+       git_reference_free(ref);
+}
diff --git a/tests/remote/httpproxy.c b/tests/remote/httpproxy.c
new file mode 100644 (file)
index 0000000..8cd4371
--- /dev/null
@@ -0,0 +1,188 @@
+#include "clar_libgit2.h"
+#include "futils.h"
+#include "net.h"
+#include "remote.h"
+
+static git_repository *repo;
+static git_net_url url = GIT_NET_URL_INIT;
+
+static int orig_proxies_need_reset = 0;
+static char *orig_http_proxy = NULL;
+static char *orig_https_proxy = NULL;
+static char *orig_no_proxy = NULL;
+
+void test_remote_httpproxy__initialize(void)
+{
+       git_remote *remote;
+
+       repo = cl_git_sandbox_init("testrepo");
+       cl_git_pass(git_remote_create(&remote, repo, "lg2", "https://github.com/libgit2/libgit2"));
+       cl_git_pass(git_net_url_parse(&url, "https://github.com/libgit2/libgit2"));
+
+       git_remote_free(remote);
+
+       orig_proxies_need_reset = 0;
+}
+
+void test_remote_httpproxy__cleanup(void)
+{
+       if (orig_proxies_need_reset) {
+               cl_setenv("HTTP_PROXY", orig_http_proxy);
+               cl_setenv("HTTPS_PROXY", orig_https_proxy);
+               cl_setenv("NO_PROXY", orig_no_proxy);
+
+               git__free(orig_http_proxy);
+               git__free(orig_https_proxy);
+               git__free(orig_no_proxy);
+       }
+
+       git_net_url_dispose(&url);
+       cl_git_sandbox_cleanup();
+}
+
+void assert_proxy_is(const char *expected)
+{
+       git_remote *remote;
+       char *proxy;
+
+       cl_git_pass(git_remote_lookup(&remote, repo, "lg2"));
+       cl_git_pass(git_remote__http_proxy(&proxy, remote, &url));
+
+       if (expected)
+               cl_assert_equal_s(proxy, expected);
+       else
+               cl_assert_equal_p(proxy, expected);
+
+       git_remote_free(remote);
+       git__free(proxy);
+}
+
+void assert_config_match(const char *config, const char *expected)
+{
+       git_remote *remote;
+       char *proxy;
+
+       if (config)
+               cl_repo_set_string(repo, config, expected);
+
+       cl_git_pass(git_remote_lookup(&remote, repo, "lg2"));
+       cl_git_pass(git_remote__http_proxy(&proxy, remote, &url));
+
+       if (expected)
+               cl_assert_equal_s(proxy, expected);
+       else
+               cl_assert_equal_p(proxy, expected);
+
+       git_remote_free(remote);
+       git__free(proxy);
+}
+
+void test_remote_httpproxy__config_overrides(void)
+{
+       /*
+        * http.proxy should be honored, then http.<url>.proxy should
+        * be honored in increasing specificity of the url.  finally,
+        * remote.<name>.proxy is the most specific.
+        */
+       assert_config_match(NULL, NULL);
+       assert_config_match("http.proxy", "http://localhost:1/");
+       assert_config_match("http.https://github.com.proxy", "http://localhost:2/");
+       assert_config_match("http.https://github.com/.proxy", "http://localhost:3/");
+       assert_config_match("http.https://github.com/libgit2.proxy", "http://localhost:4/");
+       assert_config_match("http.https://github.com/libgit2/.proxy", "http://localhost:5/");
+       assert_config_match("http.https://github.com/libgit2/libgit2.proxy", "http://localhost:6/");
+       assert_config_match("remote.lg2.proxy", "http://localhost:7/");
+}
+
+void test_remote_httpproxy__config_empty_overrides(void)
+{
+       /*
+        * with greater specificity, an empty config entry overrides
+        * a set one
+        */
+       assert_config_match("http.proxy", "http://localhost:1/");
+       assert_config_match("http.https://github.com.proxy", "");
+       assert_config_match("http.https://github.com/libgit2/libgit2.proxy", "http://localhost:2/");
+       assert_config_match("remote.lg2.proxy", "");
+}
+
+void assert_global_config_match(const char *config, const char *expected)
+{
+       git_remote *remote;
+       char *proxy;
+       git_config* cfg;
+
+       if (config) {
+               cl_git_pass(git_config_open_default(&cfg));
+               git_config_set_string(cfg, config, expected);
+               git_config_free(cfg);
+       }
+
+       cl_git_pass(git_remote_create_detached(&remote, "https://github.com/libgit2/libgit2"));
+       cl_git_pass(git_remote__http_proxy(&proxy, remote, &url));
+
+       if (expected)
+               cl_assert_equal_s(proxy, expected);
+       else
+               cl_assert_equal_p(proxy, expected);
+
+       git_remote_free(remote);
+       git__free(proxy);
+}
+
+void test_remote_httpproxy__config_overrides_detached_remote(void)
+{
+       cl_fake_home();
+
+       assert_global_config_match(NULL, NULL);
+       assert_global_config_match("http.proxy", "http://localhost:1/");
+       assert_global_config_match("http.https://github.com.proxy", "http://localhost:2/");
+       assert_global_config_match("http.https://github.com/.proxy", "http://localhost:3/");
+       assert_global_config_match("http.https://github.com/libgit2.proxy", "http://localhost:4/");
+       assert_global_config_match("http.https://github.com/libgit2/.proxy", "http://localhost:5/");
+       assert_global_config_match("http.https://github.com/libgit2/libgit2.proxy", "http://localhost:6/");
+
+       cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
+}
+
+void test_remote_httpproxy__env(void)
+{
+       orig_http_proxy = cl_getenv("HTTP_PROXY");
+       orig_https_proxy = cl_getenv("HTTPS_PROXY");
+       orig_no_proxy = cl_getenv("NO_PROXY");
+       orig_proxies_need_reset = 1;
+
+       /* Clear everything for a fresh start */
+       cl_setenv("HTTP_PROXY", NULL);
+       cl_setenv("HTTPS_PROXY", NULL);
+       cl_setenv("NO_PROXY", NULL);
+
+       /* HTTP proxy is ignored for HTTPS */
+       cl_setenv("HTTP_PROXY", "http://localhost:9/");
+       assert_proxy_is(NULL);
+
+       /* HTTPS proxy is honored for HTTPS */
+       cl_setenv("HTTPS_PROXY", "http://localhost:10/");
+       assert_proxy_is("http://localhost:10/");
+
+       /* NO_PROXY is honored */
+       cl_setenv("NO_PROXY", "github.com:443");
+       assert_proxy_is(NULL);
+
+       cl_setenv("NO_PROXY", "github.com:80");
+       assert_proxy_is("http://localhost:10/");
+
+       cl_setenv("NO_PROXY", "github.com");
+       assert_proxy_is(NULL);
+
+       cl_setenv("NO_PROXY", "github.dev,github.com,github.foo");
+       assert_proxy_is(NULL);
+
+       cl_setenv("HTTPS_PROXY", "");
+       assert_proxy_is(NULL);
+
+       /* configuration overrides environment variables */
+       cl_setenv("HTTPS_PROXY", "http://localhost:10/");
+       cl_setenv("NO_PROXY", "github.none");
+       assert_config_match("http.https://github.com.proxy", "http://localhost:11/");
+}
diff --git a/tests/repo/extensions.c b/tests/repo/extensions.c
new file mode 100644 (file)
index 0000000..e7772ac
--- /dev/null
@@ -0,0 +1,72 @@
+#include "clar_libgit2.h"
+#include "futils.h"
+#include "sysdir.h"
+#include <ctype.h>
+
+git_repository *repo;
+
+void test_repo_extensions__initialize(void)
+{
+       git_config *config;
+
+       repo = cl_git_sandbox_init("empty_bare.git");
+
+       cl_git_pass(git_repository_config(&config, repo));
+       cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
+       git_config_free(config);
+}
+
+void test_repo_extensions__cleanup(void)
+{
+       cl_git_sandbox_cleanup();
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, NULL, 0));
+}
+
+void test_repo_extensions__builtin(void)
+{
+       git_repository *extended;
+
+       cl_repo_set_string(repo, "extensions.noop", "foobar");
+
+       cl_git_pass(git_repository_open(&extended, "empty_bare.git"));
+       cl_assert(git_repository_path(extended) != NULL);
+       cl_assert(git__suffixcmp(git_repository_path(extended), "/") == 0);
+       git_repository_free(extended);
+}
+
+void test_repo_extensions__negate_builtin(void)
+{
+       const char *in[] = { "foo", "!noop", "baz" };
+       git_repository *extended;
+
+       cl_repo_set_string(repo, "extensions.noop", "foobar");
+
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
+
+       cl_git_fail(git_repository_open(&extended, "empty_bare.git"));
+       git_repository_free(extended);
+}
+
+void test_repo_extensions__unsupported(void)
+{
+       git_repository *extended = NULL;
+
+       cl_repo_set_string(repo, "extensions.unknown", "foobar");
+
+       cl_git_fail(git_repository_open(&extended, "empty_bare.git"));
+       git_repository_free(extended);
+}
+
+void test_repo_extensions__adds_extension(void)
+{
+       const char *in[] = { "foo", "!noop", "newextension", "baz" };
+       git_repository *extended;
+
+       cl_repo_set_string(repo, "extensions.newextension", "foobar");
+       cl_git_pass(git_libgit2_opts(GIT_OPT_SET_EXTENSIONS, in, ARRAY_SIZE(in)));
+
+       cl_git_pass(git_repository_open(&extended, "empty_bare.git"));
+       cl_assert(git_repository_path(extended) != NULL);
+       cl_assert(git__suffixcmp(git_repository_path(extended), "/") == 0);
+       git_repository_free(extended);
+}
index b8ede126c1d209287f23ddeda6ee4e340ed8874e..d401bb8327f2095d816a7e067441de366ba4d0f9 100644 (file)
@@ -1,4 +1,5 @@
 #include "clar_libgit2.h"
+#include "repo/repo_helpers.h"
 
 void test_repo_getters__is_empty_correctly_deals_with_pristine_looking_repos(void)
 {
@@ -23,6 +24,18 @@ void test_repo_getters__is_empty_can_detect_used_repositories(void)
        git_repository_free(repo);
 }
 
+void test_repo_getters__is_empty_can_detect_repositories_with_defaultbranch_config_empty(void)
+{
+       git_repository *repo;
+
+       create_tmp_global_config("tmp_global_path", "init.defaultBranch", "");
+
+       cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+       cl_assert_equal_i(false, git_repository_is_empty(repo));
+
+       git_repository_free(repo);
+}
+
 void test_repo_getters__retrieving_the_odb_honors_the_refcount(void)
 {
        git_odb *odb;
index 0fb4e6772a1e10cb9b0bd83fe47134a56dcd72d8..bffb51bb56b839776c34e9677b83f3298502af98 100644 (file)
@@ -10,6 +10,7 @@ void test_repo_hashfile__initialize(void)
 
 void test_repo_hashfile__cleanup(void)
 {
+       cl_fixture_cleanup("absolute");
        cl_git_sandbox_cleanup();
        _repo = NULL;
 }
@@ -38,10 +39,18 @@ void test_repo_hashfile__simple(void)
        git_buf_dispose(&full);
 }
 
-void test_repo_hashfile__filtered(void)
+void test_repo_hashfile__filtered_in_workdir(void)
 {
+       git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT;
+       char cwd[GIT_PATH_MAX];
        git_oid a, b;
 
+       cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX));
+       cl_must_pass(p_mkdir("absolute", 0777));
+       cl_git_pass(git_buf_joinpath(&root, cwd, "status"));
+       cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt"));
+       cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin"));
+
        cl_repo_set_bool(_repo, "core.autocrlf", true);
 
        cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n");
@@ -55,21 +64,41 @@ void test_repo_hashfile__filtered(void)
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, NULL));
        cl_assert(git_oid_cmp(&a, &b));
 
+       /* not equal hashes because of filtering when specified by absolute path */
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL));
+       cl_assert(git_oid_cmp(&a, &b));
+
        /* equal hashes because filter is binary */
        cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, NULL));
        cl_assert_equal_oid(&a, &b);
 
+       /* equal hashes because filter is binary when specified by absolute path */
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL));
+       cl_assert_equal_oid(&a, &b);
+
        /* equal hashes when 'as_file' points to binary filtering */
        cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "foo.bin"));
        cl_assert_equal_oid(&a, &b);
 
+       /* equal hashes when 'as_file' points to binary filtering (absolute path) */
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "foo.bin"));
+       cl_assert_equal_oid(&a, &b);
+
        /* not equal hashes when 'as_file' points to text filtering */
        cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "foo.txt"));
        cl_assert(git_oid_cmp(&a, &b));
 
+       /* not equal hashes when 'as_file' points to text filtering */
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "foo.txt"));
+       cl_assert(git_oid_cmp(&a, &b));
+
        /* equal hashes when 'as_file' is empty and turns off filtering */
        cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, ""));
@@ -79,7 +108,65 @@ void test_repo_hashfile__filtered(void)
        cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, ""));
        cl_assert_equal_oid(&a, &b);
 
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, ""));
+       cl_assert_equal_oid(&a, &b);
+
+       cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, ""));
+       cl_assert_equal_oid(&a, &b);
+
        /* some hash type failures */
        cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0));
        cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_ANY, NULL));
+
+       git_buf_dispose(&txt);
+       git_buf_dispose(&bin);
+       git_buf_dispose(&root);
+}
+
+void test_repo_hashfile__filtered_outside_workdir(void)
+{
+       git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT;
+       char cwd[GIT_PATH_MAX];
+       git_oid a, b;
+
+       cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX));
+       cl_must_pass(p_mkdir("absolute", 0777));
+       cl_git_pass(git_buf_joinpath(&root, cwd, "absolute"));
+       cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt"));
+       cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin"));
+
+       cl_repo_set_bool(_repo, "core.autocrlf", true);
+       cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n");
+
+       /* create some sample content with CRLF in it */
+       cl_git_mkfile("absolute/testfile.txt", "content\r\n");
+       cl_git_mkfile("absolute/testfile.bin", "other\r\nstuff\r\n");
+
+       /* not equal hashes because of filtering */
+       cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "testfile.txt"));
+       cl_assert(git_oid_cmp(&a, &b));
+
+       /* equal hashes because filter is binary */
+       cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "testfile.bin"));
+       cl_assert_equal_oid(&a, &b);
+
+       /*
+        * equal hashes because no filtering occurs for absolute paths outside the working
+        * directory unless as_path is specified
+        */
+       cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL));
+       cl_assert_equal_oid(&a, &b);
+
+       cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB));
+       cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL));
+       cl_assert_equal_oid(&a, &b);
+
+       git_buf_dispose(&txt);
+       git_buf_dispose(&bin);
+       git_buf_dispose(&root);
 }
index ba00d2918eb0d45181ea1a2608cc95eb74e56e1e..1aa326f7f0137c5e17bd86d0f8875cdab0d1bf9a 100644 (file)
@@ -11,30 +11,30 @@ enum repo_mode {
        BARE_REPOSITORY = 1
 };
 
-static git_repository *_repo = NULL;
-static git_buf _global_path = GIT_BUF_INIT;
+static git_repository *g_repo = NULL;
+static git_buf g_global_path = GIT_BUF_INIT;
 
 void test_repo_init__initialize(void)
 {
-       _repo = NULL;
+       g_repo = NULL;
 
        git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
-                        &_global_path);
+                        &g_global_path);
 }
 
 void test_repo_init__cleanup(void)
 {
        git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
-               _global_path.ptr);
-       git_buf_dispose(&_global_path);
+               g_global_path.ptr);
+       git_buf_dispose(&g_global_path);
 
        cl_fixture_cleanup("tmp_global_path");
 }
 
 static void cleanup_repository(void *path)
 {
-       git_repository_free(_repo);
-       _repo = NULL;
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        cl_fixture_cleanup((const char *)path);
 }
@@ -49,9 +49,9 @@ static void ensure_repository_init(
 
        cl_assert(!git_path_isdir(working_directory));
 
-       cl_git_pass(git_repository_init(&_repo, working_directory, is_bare));
+       cl_git_pass(git_repository_init(&g_repo, working_directory, is_bare));
 
-       workdir = git_repository_workdir(_repo);
+       workdir = git_repository_workdir(g_repo);
        if (workdir != NULL || expected_working_directory != NULL) {
                cl_assert(
                        git__suffixcmp(workdir, expected_working_directory) == 0
@@ -59,19 +59,19 @@ static void ensure_repository_init(
        }
 
        cl_assert(
-               git__suffixcmp(git_repository_path(_repo), expected_path_repository) == 0
+               git__suffixcmp(git_repository_path(g_repo), expected_path_repository) == 0
        );
 
-       cl_assert(git_repository_is_bare(_repo) == is_bare);
+       cl_assert(git_repository_is_bare(g_repo) == is_bare);
 
 #ifdef GIT_WIN32
        if (!is_bare) {
-               DWORD fattrs = GetFileAttributes(git_repository_path(_repo));
+               DWORD fattrs = GetFileAttributes(git_repository_path(g_repo));
                cl_assert((fattrs & FILE_ATTRIBUTE_HIDDEN) != 0);
        }
 #endif
 
-       cl_assert(git_repository_is_empty(_repo));
+       cl_assert(git_repository_is_empty(g_repo));
 }
 
 void test_repo_init__standard_repo(void)
@@ -112,13 +112,14 @@ void test_repo_init__bare_repo_escaping_current_workdir(void)
        cl_git_pass(chdir(git_buf_cstr(&path_repository)));
 
        /* Initialize a bare repo with a relative path escaping out of the current working directory */
-       cl_git_pass(git_repository_init(&_repo, "../d/e.git", 1));
-       cl_git_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/"));
+       cl_git_pass(git_repository_init(&g_repo, "../d/e.git", 1));
+       cl_git_pass(git__suffixcmp(git_repository_path(g_repo), "/a/b/d/e.git/"));
 
-       git_repository_free(_repo);
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        /* Open a bare repo with a relative path escaping out of the current working directory */
-       cl_git_pass(git_repository_open(&_repo, "../d/e.git"));
+       cl_git_pass(git_repository_open(&g_repo, "../d/e.git"));
 
        cl_git_pass(chdir(git_buf_cstr(&path_current_workdir)));
 
@@ -133,11 +134,12 @@ void test_repo_init__reinit_bare_repo(void)
        cl_set_cleanup(&cleanup_repository, "reinit.git");
 
        /* Initialize the repository */
-       cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
-       git_repository_free(_repo);
+       cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        /* Reinitialize the repository */
-       cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
+       cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
 }
 
 void test_repo_init__reinit_too_recent_bare_repo(void)
@@ -145,8 +147,8 @@ void test_repo_init__reinit_too_recent_bare_repo(void)
        git_config *config;
 
        /* Initialize the repository */
-       cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
-       git_repository_config(&config, _repo);
+       cl_git_pass(git_repository_init(&g_repo, "reinit.git", 1));
+       git_repository_config(&config, g_repo);
 
        /*
         * Hack the config of the repository to make it look like it has
@@ -155,10 +157,11 @@ void test_repo_init__reinit_too_recent_bare_repo(void)
        cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 42));
 
        git_config_free(config);
-       git_repository_free(_repo);
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        /* Try to reinitialize the repository */
-       cl_git_fail(git_repository_init(&_repo, "reinit.git", 1));
+       cl_git_fail(git_repository_init(&g_repo, "reinit.git", 1));
 
        cl_fixture_cleanup("reinit.git");
 }
@@ -172,15 +175,15 @@ void test_repo_init__additional_templates(void)
        ensure_repository_init("tester", 0, "tester/.git/", "tester/");
 
        cl_git_pass(
-               git_buf_joinpath(&path, git_repository_path(_repo), "description"));
+               git_buf_joinpath(&path, git_repository_path(g_repo), "description"));
        cl_assert(git_path_isfile(git_buf_cstr(&path)));
 
        cl_git_pass(
-               git_buf_joinpath(&path, git_repository_path(_repo), "info/exclude"));
+               git_buf_joinpath(&path, git_repository_path(g_repo), "info/exclude"));
        cl_assert(git_path_isfile(git_buf_cstr(&path)));
 
        cl_git_pass(
-               git_buf_joinpath(&path, git_repository_path(_repo), "hooks"));
+               git_buf_joinpath(&path, git_repository_path(g_repo), "hooks"));
        cl_assert(git_path_isdir(git_buf_cstr(&path)));
        /* won't confirm specific contents of hooks dir since it may vary */
 
@@ -197,9 +200,9 @@ static void assert_config_entry_on_init_bytype(
 
        cl_set_cleanup(&cleanup_repository, "config_entry");
 
-       cl_git_pass(git_repository_init(&_repo, repo_path, is_bare));
+       cl_git_pass(git_repository_init(&g_repo, repo_path, is_bare));
 
-       cl_git_pass(git_repository_config(&config, _repo));
+       cl_git_pass(git_repository_config(&config, g_repo));
        error = git_config_get_bool(&current_value, config, config_key);
        git_config_free(config);
 
@@ -215,7 +218,8 @@ static void assert_config_entry_on_init(
        const char *config_key, int expected_value)
 {
        assert_config_entry_on_init_bytype(config_key, expected_value, true);
-       git_repository_free(_repo);
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        assert_config_entry_on_init_bytype(config_key, expected_value, false);
 }
@@ -262,10 +266,10 @@ void test_repo_init__symlinks_win32_enabled_by_global_config(void)
         * Create a new repository (can't use `assert_config_on_init` since we
         * want to examine configuration levels with more granularity.)
         */
-       cl_git_pass(git_repository_init(&_repo, "config_entry/test.non.bare.git", false));
+       cl_git_pass(git_repository_init(&g_repo, "config_entry/test.non.bare.git", false));
 
        /* Ensure that core.symlinks remains set (via the global config). */
-       cl_git_pass(git_repository_config(&config, _repo));
+       cl_git_pass(git_repository_config(&config, g_repo));
        cl_git_pass(git_config_get_bool(&val, config, "core.symlinks"));
        cl_assert_equal_i(1, val);
 
@@ -278,6 +282,9 @@ void test_repo_init__symlinks_win32_enabled_by_global_config(void)
        git_config_free(repo_config);
 
        git_config_free(config);
+
+       git_repository_free(g_repo);
+       g_repo = NULL;
 #endif
 }
 
@@ -324,18 +331,18 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
 
        /* Init a new repo */
        cl_set_cleanup(&cleanup_repository, "not.overwrite.git");
-       cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
+       cl_git_pass(git_repository_init(&g_repo, "not.overwrite.git", 1));
 
        /* Change the "core.ignorecase" config value to something unlikely */
-       git_repository_config(&config, _repo);
+       git_repository_config(&config, g_repo);
        git_config_set_int32(config, "core.ignorecase", 42);
        git_config_free(config);
-       git_repository_free(_repo);
-       _repo = NULL;
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        /* Reinit the repository */
-       cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
-       git_repository_config(&config, _repo);
+       cl_git_pass(git_repository_init(&g_repo, "not.overwrite.git", 1));
+       git_repository_config(&config, g_repo);
 
        /* Ensure the "core.ignorecase" config value hasn't been updated */
        cl_git_pass(git_config_get_int32(&current_value, config, "core.ignorecase"));
@@ -350,26 +357,26 @@ void test_repo_init__reinit_overwrites_filemode(void)
 
        /* Init a new repo */
        cl_set_cleanup(&cleanup_repository, "overwrite.git");
-       cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
+       cl_git_pass(git_repository_init(&g_repo, "overwrite.git", 1));
 
        /* Change the "core.filemode" config value to something unlikely */
-       cl_repo_set_bool(_repo, "core.filemode", !expected);
+       cl_repo_set_bool(g_repo, "core.filemode", !expected);
 
-       git_repository_free(_repo);
-       _repo = NULL;
+       git_repository_free(g_repo);
+       g_repo = NULL;
 
        /* Reinit the repository */
-       cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
+       cl_git_pass(git_repository_init(&g_repo, "overwrite.git", 1));
 
        /* Ensure the "core.filemode" config value has been reset */
-       current_value = cl_repo_get_bool(_repo, "core.filemode");
+       current_value = cl_repo_get_bool(g_repo, "core.filemode");
        cl_assert_equal_i(expected, current_value);
 }
 
 void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
 {
        assert_config_entry_on_init_bytype("core.logallrefupdates", GIT_ENOTFOUND, true);
-       git_repository_free(_repo);
+       git_repository_free(g_repo);
        assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
 }
 
@@ -378,16 +385,16 @@ void test_repo_init__extended_0(void)
        git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
 
        /* without MKDIR this should fail */
-       cl_git_fail(git_repository_init_ext(&_repo, "extended", &opts));
+       cl_git_fail(git_repository_init_ext(&g_repo, "extended", &opts));
 
        /* make the directory first, then it should succeed */
        cl_git_pass(git_futils_mkdir("extended", 0775, 0));
-       cl_git_pass(git_repository_init_ext(&_repo, "extended", &opts));
+       cl_git_pass(git_repository_init_ext(&g_repo, "extended", &opts));
 
-       cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/extended/"));
-       cl_assert(!git__suffixcmp(git_repository_path(_repo), "/extended/.git/"));
-       cl_assert(!git_repository_is_bare(_repo));
-       cl_assert(git_repository_is_empty(_repo));
+       cl_assert(!git__suffixcmp(git_repository_workdir(g_repo), "/extended/"));
+       cl_assert(!git__suffixcmp(git_repository_path(g_repo), "/extended/.git/"));
+       cl_assert(!git_repository_is_bare(g_repo));
+       cl_assert(git_repository_is_empty(g_repo));
 
        cleanup_repository("extended");
 }
@@ -407,33 +414,33 @@ void test_repo_init__extended_1(void)
        opts.initial_head = "development";
        opts.origin_url = "https://github.com/libgit2/libgit2.git";
 
-       cl_git_pass(git_repository_init_ext(&_repo, "root/b/c.git", &opts));
+       cl_git_pass(git_repository_init_ext(&g_repo, "root/b/c.git", &opts));
 
-       cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/c_wd/"));
-       cl_assert(!git__suffixcmp(git_repository_path(_repo), "/c.git/"));
+       cl_assert(!git__suffixcmp(git_repository_workdir(g_repo), "/c_wd/"));
+       cl_assert(!git__suffixcmp(git_repository_path(g_repo), "/c.git/"));
        cl_assert(git_path_isfile("root/b/c_wd/.git"));
-       cl_assert(!git_repository_is_bare(_repo));
+       cl_assert(!git_repository_is_bare(g_repo));
        /* repo will not be counted as empty because we set head to "development" */
-       cl_assert(!git_repository_is_empty(_repo));
+       cl_assert(!git_repository_is_empty(g_repo));
 
-       cl_git_pass(git_path_lstat(git_repository_path(_repo), &st));
+       cl_git_pass(git_path_lstat(git_repository_path(g_repo), &st));
        cl_assert(S_ISDIR(st.st_mode));
        if (cl_is_chmod_supported())
                cl_assert((S_ISGID & st.st_mode) == S_ISGID);
        else
                cl_assert((S_ISGID & st.st_mode) == 0);
 
-       cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD"));
+       cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
        cl_assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
        cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref));
        git_reference_free(ref);
 
-       cl_git_pass(git_remote_lookup(&remote, _repo, "origin"));
+       cl_git_pass(git_remote_lookup(&remote, g_repo, "origin"));
        cl_assert_equal_s("origin", git_remote_name(remote));
        cl_assert_equal_s(opts.origin_url, git_remote_url(remote));
        git_remote_free(remote);
 
-       git_repository_free(_repo);
+       git_repository_free(g_repo);
        cl_fixture_cleanup("root");
 }
 
@@ -449,17 +456,17 @@ void test_repo_init__relative_gitdir(void)
                GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
 
        /* make the directory first, then it should succeed */
-       cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
+       cl_git_pass(git_repository_init_ext(&g_repo, "root/b/my_repository", &opts));
 
-       cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
-       cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
-       cl_assert(!git_repository_is_bare(_repo));
-       cl_assert(git_repository_is_empty(_repo));
+       cl_assert(!git__suffixcmp(git_repository_workdir(g_repo), "root/b/c_wd/"));
+       cl_assert(!git__suffixcmp(git_repository_path(g_repo), "root/b/my_repository/"));
+       cl_assert(!git_repository_is_bare(g_repo));
+       cl_assert(git_repository_is_empty(g_repo));
 
        /* Verify that the gitlink and worktree entries are relative */
 
        /* Verify worktree */
-       assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
+       assert_config_entry_value(g_repo, "core.worktree", "../c_wd/");
 
        /* Verify gitlink */
        cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
@@ -485,18 +492,18 @@ void test_repo_init__relative_gitdir_2(void)
                GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
 
        /* make the directory first, then it should succeed */
-       cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
+       cl_git_pass(git_repository_init_ext(&g_repo, "root/b/my_repository", &opts));
        git_buf_dispose(&full_path);
 
-       cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
-       cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
-       cl_assert(!git_repository_is_bare(_repo));
-       cl_assert(git_repository_is_empty(_repo));
+       cl_assert(!git__suffixcmp(git_repository_workdir(g_repo), "root/b/c_wd/"));
+       cl_assert(!git__suffixcmp(git_repository_path(g_repo), "root/b/my_repository/"));
+       cl_assert(!git_repository_is_bare(g_repo));
+       cl_assert(git_repository_is_empty(g_repo));
 
        /* Verify that the gitlink and worktree entries are relative */
 
        /* Verify worktree */
-       assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
+       assert_config_entry_value(g_repo, "core.worktree", "../c_wd/");
 
        /* Verify gitlink */
        cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
@@ -513,11 +520,11 @@ void test_repo_init__can_reinit_an_initialized_repository(void)
        cl_set_cleanup(&cleanup_repository, "extended");
 
        cl_git_pass(git_futils_mkdir("extended", 0775, 0));
-       cl_git_pass(git_repository_init(&_repo, "extended", false));
+       cl_git_pass(git_repository_init(&g_repo, "extended", false));
 
        cl_git_pass(git_repository_init(&reinit, "extended", false));
 
-       cl_assert_equal_s(git_repository_path(_repo), git_repository_path(reinit));
+       cl_assert_equal_s(git_repository_path(g_repo), git_repository_path(reinit));
 
        git_repository_free(reinit);
 }
@@ -529,10 +536,10 @@ void test_repo_init__init_with_initial_commit(void)
        cl_set_cleanup(&cleanup_repository, "committed");
 
        /* Initialize the repository */
-       cl_git_pass(git_repository_init(&_repo, "committed", 0));
+       cl_git_pass(git_repository_init(&g_repo, "committed", 0));
 
        /* Index will be automatically created when requested for a new repo */
-       cl_git_pass(git_repository_index(&index, _repo));
+       cl_git_pass(git_repository_index(&index, g_repo));
 
        /* Create a file so we can commit it
         *
@@ -558,7 +565,7 @@ void test_repo_init__init_with_initial_commit(void)
        /* Make sure we're ready to use git_signature_default :-) */
        {
                git_config *cfg, *local;
-               cl_git_pass(git_repository_config(&cfg, _repo));
+               cl_git_pass(git_repository_config(&cfg, g_repo));
                cl_git_pass(git_config_open_level(&local, cfg, GIT_CONFIG_LEVEL_LOCAL));
                cl_git_pass(git_config_set_string(local, "user.name", "Test User"));
                cl_git_pass(git_config_set_string(local, "user.email", "t@example.com"));
@@ -572,12 +579,12 @@ void test_repo_init__init_with_initial_commit(void)
                git_oid tree_id, commit_id;
                git_tree *tree;
 
-               cl_git_pass(git_signature_default(&sig, _repo));
+               cl_git_pass(git_signature_default(&sig, g_repo));
                cl_git_pass(git_index_write_tree(&tree_id, index));
-               cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
+               cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
 
                cl_git_pass(git_commit_create_v(
-                       &commit_id, _repo, "HEAD", sig, sig,
+                       &commit_id, g_repo, "HEAD", sig, sig,
                        NULL, "First", tree, 0));
 
                git_tree_free(tree);
@@ -674,10 +681,58 @@ void test_repo_init__defaultbranch_config(void)
 
        create_tmp_global_config("tmp_global_path", "init.defaultbranch", "my_default_branch");
 
-       cl_git_pass(git_repository_init(&_repo, "repo", 0));
-       cl_git_pass(git_reference_lookup(&head, _repo, "HEAD"));
+       cl_git_pass(git_repository_init(&g_repo, "repo", 0));
+       cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
 
        cl_assert_equal_s("refs/heads/my_default_branch", git_reference_symbolic_target(head));
 
        git_reference_free(head);
 }
+
+void test_repo_init__defaultbranch_config_empty(void)
+{
+       git_reference *head;
+
+       cl_set_cleanup(&cleanup_repository, "repo");
+
+       create_tmp_global_config("tmp_global_path", "init.defaultbranch", "");
+
+       cl_git_pass(git_repository_init(&g_repo, "repo", 0));
+       cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
+
+       cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
+
+       git_reference_free(head);
+}
+
+void test_repo_init__longpath(void)
+{
+#ifdef GIT_WIN32
+       size_t padding = CONST_STRLEN("objects/pack/pack-.pack.lock") + GIT_OID_HEXSZ;
+       size_t max, i;
+       git_buf path = GIT_BUF_INIT;
+       git_repository *one = NULL, *two = NULL;
+
+       /*
+        * Files within repositories need to fit within MAX_PATH;
+        * that means a repo path must be at most (MAX_PATH - 18).
+        */
+       cl_git_pass(git_buf_puts(&path, clar_sandbox_path()));
+       cl_git_pass(git_buf_putc(&path, '/'));
+
+       max = ((MAX_PATH) - path.size) - padding;
+
+       for (i = 0; i < max - 1; i++)
+               cl_git_pass(git_buf_putc(&path, 'a'));
+
+       cl_git_pass(git_repository_init(&one, path.ptr, 1));
+
+       /* Paths longer than this are rejected */
+       cl_git_pass(git_buf_putc(&path, 'z'));
+       cl_git_fail(git_repository_init(&two, path.ptr, 1));
+
+       git_repository_free(one);
+       git_repository_free(two);
+       git_buf_dispose(&path);
+#endif
+}
index 881a23d34e50f6218e593d3d7f2a4e1417ca93d3..bd60c12c29b2834e3aff442433bf694485a2b5b2 100644 (file)
@@ -42,48 +42,6 @@ void test_repo_open__format_version_1(void)
        git_repository_free(repo);
 }
 
-void test_repo_open__format_version_1_with_valid_extension(void)
-{
-       git_repository *repo;
-       git_config *config;
-
-       repo = cl_git_sandbox_init("empty_bare.git");
-
-       cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
-       cl_git_pass(git_repository_config(&config, repo));
-
-       cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
-       cl_git_pass(git_config_set_int32(config, "extensions.noop", 1));
-
-       git_config_free(config);
-       git_repository_free(repo);
-
-       cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
-       cl_assert(git_repository_path(repo) != NULL);
-       cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
-       git_repository_free(repo);
-}
-
-void test_repo_open__format_version_1_with_invalid_extension(void)
-{
-       git_repository *repo;
-       git_config *config;
-
-       repo = cl_git_sandbox_init("empty_bare.git");
-
-       cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
-       cl_git_pass(git_repository_config(&config, repo));
-
-       cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
-       cl_git_pass(git_config_set_int32(config, "extensions.invalid", 1));
-
-       git_config_free(config);
-       git_repository_free(repo);
-
-       cl_git_fail(git_repository_open(&repo, "empty_bare.git"));
-       git_repository_free(repo);
-}
-
 void test_repo_open__standard_empty_repo_through_gitdir(void)
 {
        git_repository *repo;
diff --git a/tests/resources/certs/61f2ddb6.0 b/tests/resources/certs/61f2ddb6.0
new file mode 100644 (file)
index 0000000..7d9ef6f
--- /dev/null
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWzCCA0MCFESY816VkhBPUOsdp7djKW5q4ZVzMA0GCSqGSIb3DQEBCwUAMGox
+CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD
+YW1icmlkZ2UxFDASBgNVBAoMC2xpYmdpdDIub3JnMRkwFwYDVQQDDBB0ZXN0Lmxp
+YmdpdDIub3JnMB4XDTIxMDgyNTE4NTExMVoXDTMxMDgyMzE4NTExMVowajELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJy
+aWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRlc3QubGliZ2l0
+Mi5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvaRUaM3IJh9N
+G6Yc7tHioUsIGU0MkzSvy/X6O/vONnuuioiJQyPIvfRSvZR2iQj8THTypDGhWn3r
+6h2wk5eOUGwJH2N9FrrlEBdpsMc7SKdiJXwTI30mkK3/qru8NzE71dgCkYp1xhKw
+edTkAFK+PkvyVLFL7K35cx8Bxfamyssdb+qGWa7g4P27CWUdvQgmurrzzPIMZiLD
+/cI1Kwer/N7nTY/6CSs9dcHTlanyZdf+mQ50+//vI4F6+OduGHJkxRF48jLUz1rz
+P3WGRMRbHjCmvWpX/9DLgqGk7XTy0hNgNUCit6kawwcv5y7SP/ii86MkynAHn5i8
+d+zhXjdrSSy8i0IbRJafnxmtrsmjGeIzraJSRqMlv7KKWEBz+alm6vlePnRUbWB7
+0po5uSsRPya6kJJCzMjIfKq1dgXq33m9jCG2wU+L4fEHVlEkFGXYTspMlIBNUjTc
+c45+e1EpamF8aHm32PP8gTF8fGZzQjOXmNW5g7t0joWMGZ+Ao2jYc1pG3SOARi36
+azrmB5/XJqbbfVZEzIue01fO/5R8RgabOP1qWUjH2KLb8zTDok+CW0ULNseU+MKf
+PHXG2OjxcR0vTqop2V6JlKTXXx3/TOD16/+mSrrPzNDejLrkvAH9oN38YpMBM8eg
+vfivHNRm0jjdGbv2OOPEBLEf1cNimQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBZ
+znFta24sWoqdgKXKAK5RHAh/HyOvTInwcXi9RU4XjYlbqNVs0ODR74VRZINoyAL2
+bo+x/iUuAp9+b8fjr79fpVof3nSMU7UtMcT1nvzVmaUYSkKQ0f/9vK4yg0kao1bV
+WwhIc0slKgOJjEicPVs3kd+duv5vakQeUajLPGM8SiS1F/nF67rIuZLdJn2Qp+im
+w5Q3Pjgqw5VrJxyk3AaUcntKHpWy1POLyNV79tXra6BxbtQVlRS0+h1MHELARDFx
+1ZtgyAe5YbWM7WrIiFKD4mmKZu4GMnJDXVpfUub5g0U/e7L/gg6Z1UyYZuln6axw
+RojuAHo1uAWFUsjhWLYV/7P/l/dC+7gFjvSsUqb1+U7jXObzfKjXo/FwYcy4VsVv
+xNbglbhdVjAo/YBTJuf3L0UZjSbxvQIYS+v8u1ECeWE6SH6cHRzryeo5wO4h8NJR
+n30xsvocHFbs4LWy5BVfMUo6wGUy0Y+1gSwSqVMv3JPuLwxUsv0HPdeC00Ab9cHq
+kYXPNZXg3a6orTDa4hJLdAm2V/fn/2KKJYlNj7iCL664QgoCHl7LFyLMiwFVCu5h
+4JjGL3Q+8MondaLZlq5YDmvtj979AyM/7qL4XAE2oofQ4J5dqnKKpMkWdAM/fI/9
+N5DK/4zMXJWgIED0yo2SSZHQmuqZplacOhmfjjZigQ==
+-----END CERTIFICATE-----
diff --git a/tests/resources/certs/db4f60b0.0 b/tests/resources/certs/db4f60b0.0
new file mode 100644 (file)
index 0000000..7d9ef6f
--- /dev/null
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWzCCA0MCFESY816VkhBPUOsdp7djKW5q4ZVzMA0GCSqGSIb3DQEBCwUAMGox
+CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD
+YW1icmlkZ2UxFDASBgNVBAoMC2xpYmdpdDIub3JnMRkwFwYDVQQDDBB0ZXN0Lmxp
+YmdpdDIub3JnMB4XDTIxMDgyNTE4NTExMVoXDTMxMDgyMzE4NTExMVowajELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJy
+aWRnZTEUMBIGA1UECgwLbGliZ2l0Mi5vcmcxGTAXBgNVBAMMEHRlc3QubGliZ2l0
+Mi5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvaRUaM3IJh9N
+G6Yc7tHioUsIGU0MkzSvy/X6O/vONnuuioiJQyPIvfRSvZR2iQj8THTypDGhWn3r
+6h2wk5eOUGwJH2N9FrrlEBdpsMc7SKdiJXwTI30mkK3/qru8NzE71dgCkYp1xhKw
+edTkAFK+PkvyVLFL7K35cx8Bxfamyssdb+qGWa7g4P27CWUdvQgmurrzzPIMZiLD
+/cI1Kwer/N7nTY/6CSs9dcHTlanyZdf+mQ50+//vI4F6+OduGHJkxRF48jLUz1rz
+P3WGRMRbHjCmvWpX/9DLgqGk7XTy0hNgNUCit6kawwcv5y7SP/ii86MkynAHn5i8
+d+zhXjdrSSy8i0IbRJafnxmtrsmjGeIzraJSRqMlv7KKWEBz+alm6vlePnRUbWB7
+0po5uSsRPya6kJJCzMjIfKq1dgXq33m9jCG2wU+L4fEHVlEkFGXYTspMlIBNUjTc
+c45+e1EpamF8aHm32PP8gTF8fGZzQjOXmNW5g7t0joWMGZ+Ao2jYc1pG3SOARi36
+azrmB5/XJqbbfVZEzIue01fO/5R8RgabOP1qWUjH2KLb8zTDok+CW0ULNseU+MKf
+PHXG2OjxcR0vTqop2V6JlKTXXx3/TOD16/+mSrrPzNDejLrkvAH9oN38YpMBM8eg
+vfivHNRm0jjdGbv2OOPEBLEf1cNimQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBZ
+znFta24sWoqdgKXKAK5RHAh/HyOvTInwcXi9RU4XjYlbqNVs0ODR74VRZINoyAL2
+bo+x/iUuAp9+b8fjr79fpVof3nSMU7UtMcT1nvzVmaUYSkKQ0f/9vK4yg0kao1bV
+WwhIc0slKgOJjEicPVs3kd+duv5vakQeUajLPGM8SiS1F/nF67rIuZLdJn2Qp+im
+w5Q3Pjgqw5VrJxyk3AaUcntKHpWy1POLyNV79tXra6BxbtQVlRS0+h1MHELARDFx
+1ZtgyAe5YbWM7WrIiFKD4mmKZu4GMnJDXVpfUub5g0U/e7L/gg6Z1UyYZuln6axw
+RojuAHo1uAWFUsjhWLYV/7P/l/dC+7gFjvSsUqb1+U7jXObzfKjXo/FwYcy4VsVv
+xNbglbhdVjAo/YBTJuf3L0UZjSbxvQIYS+v8u1ECeWE6SH6cHRzryeo5wO4h8NJR
+n30xsvocHFbs4LWy5BVfMUo6wGUy0Y+1gSwSqVMv3JPuLwxUsv0HPdeC00Ab9cHq
+kYXPNZXg3a6orTDa4hJLdAm2V/fn/2KKJYlNj7iCL664QgoCHl7LFyLMiwFVCu5h
+4JjGL3Q+8MondaLZlq5YDmvtj979AyM/7qL4XAE2oofQ4J5dqnKKpMkWdAM/fI/9
+N5DK/4zMXJWgIED0yo2SSZHQmuqZplacOhmfjjZigQ==
+-----END CERTIFICATE-----
diff --git a/tests/resources/config/config21 b/tests/resources/config/config21
new file mode 100644 (file)
index 0000000..aa5eb41
--- /dev/null
@@ -0,0 +1,5 @@
+[alias]
+       m = '\
+       ";" \
+       ";" \
+       '
diff --git a/tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb b/tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb
new file mode 100644 (file)
index 0000000..44076ca
Binary files /dev/null and b/tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb differ
diff --git a/tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d b/tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d
new file mode 100644 (file)
index 0000000..ca97967
Binary files /dev/null and b/tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d differ
diff --git a/tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c b/tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c
new file mode 100644 (file)
index 0000000..0576e62
Binary files /dev/null and b/tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c differ
diff --git a/tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0 b/tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0
new file mode 100644 (file)
index 0000000..7501c88
Binary files /dev/null and b/tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0 differ
diff --git a/tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0 b/tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0
new file mode 100644 (file)
index 0000000..d745d20
--- /dev/null
@@ -0,0 +1,3 @@
+x\ 1¥\8fM
+Â0\10\85\14s\ 1%3\19Ó\ 6Dtá\r¼À$\99bÁ6¥F¼¾Q¼\81»÷\ 3\1fï¥2Mc\ 5ònSWU`\8e6*ö¾C¡\9e\aĽGì¢w®×,\89|S\8cÉ,²ê\\ 1\89\a¦à\98Ù#\8bôYö®\ 18t\81\12);\rqÈÁȳÞÊ
+\97ü\925ÃõV¦G\99á -ý¨\93~\8b\9fÛ¥2\1d\ 1=ù`Ñ\11ÁÖ²µ¦¥mlÕ?1æ\9c\fcn\ f\rºH\1dã]a\18ïjÞ@\81U\e
\ No newline at end of file
diff --git a/tests/resources/crlf.git/refs/heads/ident b/tests/resources/crlf.git/refs/heads/ident
new file mode 100644 (file)
index 0000000..8732f0c
--- /dev/null
@@ -0,0 +1 @@
+b8986fec0f7bde90f78ac72706e782d82f24f2f0
diff --git a/tests/resources/crlf.git/refs/heads/no-ident b/tests/resources/crlf.git/refs/heads/no-ident
new file mode 100644 (file)
index 0000000..fa9a673
--- /dev/null
@@ -0,0 +1 @@
+1ec507638b806aba45d6142082885f2a9e88322d
diff --git a/tests/resources/merge-recursive/.gitted/objects/info/commit-graph b/tests/resources/merge-recursive/.gitted/objects/info/commit-graph
new file mode 100644 (file)
index 0000000..da055f1
Binary files /dev/null and b/tests/resources/merge-recursive/.gitted/objects/info/commit-graph differ
diff --git a/tests/resources/renames/.gitted/ORIG_HEAD b/tests/resources/renames/.gitted/ORIG_HEAD
new file mode 100644 (file)
index 0000000..642c319
--- /dev/null
@@ -0,0 +1 @@
+19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13
index 72363c0f52fba5560db5c0a127ddebfc47c0ba62..5882a8d605cebe2dfa9fb54c6e5fc3b610c0aced 100644 (file)
Binary files a/tests/resources/renames/.gitted/index and b/tests/resources/renames/.gitted/index differ
index e697922635af95cad6d98d82fe44b36633829162..e6da6784e093e6555bf70a94677e2f267e7153a5 100644 (file)
@@ -2,3 +2,8 @@
 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 2bc7f351d20b53f1c72c16c4b036e491c478c49a Russell Belfer <rb@github.com> 1351024817 -0700      commit: copy and rename with no change
 2bc7f351d20b53f1c72c16c4b036e491c478c49a 1c068dee5790ef1580cfc4cd670915b48d790084 Russell Belfer <rb@github.com> 1361485758 -0800      commit: rewrites, copies with changes, etc.
 1c068dee5790ef1580cfc4cd670915b48d790084 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Russell Belfer <rb@github.com> 1361486360 -0800      commit: more renames and smallish modifications
+19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 Kartikaya Gupta <kats@pancake.staktrace.com> 1618486966 -0400        checkout: moving from master to break_rewrite
+31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 db98035f715427eef1f5e17f03e1801c05301e9e Kartikaya Gupta <kats@pancake.staktrace.com> 1618487039 -0400        commit: This test needs to start with a minimum of four files
+db98035f715427eef1f5e17f03e1801c05301e9e 7e7bfb88ba9bc65fd700fee1819cf1c317aafa56 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487097 -0400        commit: Copy/modify files around
+7e7bfb88ba9bc65fd700fee1819cf1c317aafa56 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487105 -0400        checkout: moving from break_rewrite to master
+19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Kartikaya Gupta <kats@pancake.staktrace.com> 1618487271 -0400        reset: moving to HEAD
diff --git a/tests/resources/renames/.gitted/objects/41/2a2eaf2c13103ea976b3b02c17abee7a358432 b/tests/resources/renames/.gitted/objects/41/2a2eaf2c13103ea976b3b02c17abee7a358432
new file mode 100644 (file)
index 0000000..d0d3334
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/41/2a2eaf2c13103ea976b3b02c17abee7a358432 differ
diff --git a/tests/resources/renames/.gitted/objects/5a/71babaaac78a758b52576a60cea3c218c8b546 b/tests/resources/renames/.gitted/objects/5a/71babaaac78a758b52576a60cea3c218c8b546
new file mode 100644 (file)
index 0000000..e685bfa
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/5a/71babaaac78a758b52576a60cea3c218c8b546 differ
diff --git a/tests/resources/renames/.gitted/objects/7e/7bfb88ba9bc65fd700fee1819cf1c317aafa56 b/tests/resources/renames/.gitted/objects/7e/7bfb88ba9bc65fd700fee1819cf1c317aafa56
new file mode 100644 (file)
index 0000000..e53c843
--- /dev/null
@@ -0,0 +1,2 @@
+x\ 1¥\8eKn\840\10\ 5³ö)ú\ 2\99éö\a\e)\8a"e1\8b9EcÚ
+bÀÈ4\vn\1fî0ËWR\95^®Ë2)Ø\8e\89\80'ËV¸ØL\8eР      ÷±\eÜ\80×\8e<\88Dv!ygÍÆMV\85\13ºP"\ 5o£H¡\12\84b¹TJH\19\83C\92^\f\1fúW\e<¹é4óÉð86eø\9a\9f\8d×̳ÜvåY\eg¹åº|\ 3u\94|\8aØGøD\8fh.z½Uy·c~ëvÞ\97:Nå\842½d\anõXGó\ f\v©T´
\ No newline at end of file
diff --git a/tests/resources/renames/.gitted/objects/bf/102db0c9c0c1513909a90e0611b5dddfc87c93 b/tests/resources/renames/.gitted/objects/bf/102db0c9c0c1513909a90e0611b5dddfc87c93
new file mode 100644 (file)
index 0000000..69ddd68
--- /dev/null
@@ -0,0 +1,2 @@
+x\ 1+)JMU042a040031Qpttd83\83ÿ×Ñ\8f\96fÓ®\9c-°[yéï³ÚËéPi'''\86¨Â]»V\1dï*í\ e
+ÏJ8·ø\90Ä\89­nPiggg\86×\9b·¯\97U=á©«\9f\94¡vR%bû¹¿   Pi\17\17\17¬º\ 1¼:6\8e
\ No newline at end of file
diff --git a/tests/resources/renames/.gitted/objects/cc/980ffac5f1393696d4cd703ea9d2fde67dd367 b/tests/resources/renames/.gitted/objects/cc/980ffac5f1393696d4cd703ea9d2fde67dd367
new file mode 100644 (file)
index 0000000..ac7a005
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/cc/980ffac5f1393696d4cd703ea9d2fde67dd367 differ
diff --git a/tests/resources/renames/.gitted/objects/db/98035f715427eef1f5e17f03e1801c05301e9e b/tests/resources/renames/.gitted/objects/db/98035f715427eef1f5e17f03e1801c05301e9e
new file mode 100644 (file)
index 0000000..48bc2e1
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/db/98035f715427eef1f5e17f03e1801c05301e9e differ
diff --git a/tests/resources/renames/.gitted/objects/eb/b3b7af1d25c8492d2f626826c92458b7cefd60 b/tests/resources/renames/.gitted/objects/eb/b3b7af1d25c8492d2f626826c92458b7cefd60
new file mode 100644 (file)
index 0000000..813e7ad
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/eb/b3b7af1d25c8492d2f626826c92458b7cefd60 differ
diff --git a/tests/resources/renames/.gitted/objects/ed/2a95c4a6c295b9afcea50baff63ec544ccf600 b/tests/resources/renames/.gitted/objects/ed/2a95c4a6c295b9afcea50baff63ec544ccf600
new file mode 100644 (file)
index 0000000..4f439e2
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/ed/2a95c4a6c295b9afcea50baff63ec544ccf600 differ
diff --git a/tests/resources/renames/.gitted/objects/f6/7e2f70efe89665e829ea0d77c46965ad1307e4 b/tests/resources/renames/.gitted/objects/f6/7e2f70efe89665e829ea0d77c46965ad1307e4
new file mode 100644 (file)
index 0000000..1cad213
Binary files /dev/null and b/tests/resources/renames/.gitted/objects/f6/7e2f70efe89665e829ea0d77c46965ad1307e4 differ
diff --git a/tests/resources/renames/.gitted/refs/heads/break_rewrite b/tests/resources/renames/.gitted/refs/heads/break_rewrite
new file mode 100644 (file)
index 0000000..d170915
--- /dev/null
@@ -0,0 +1 @@
+7e7bfb88ba9bc65fd700fee1819cf1c317aafa56
diff --git a/tests/resources/revert-rename.git/HEAD b/tests/resources/revert-rename.git/HEAD
new file mode 100644 (file)
index 0000000..cb089cd
--- /dev/null
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/revert-rename.git/config b/tests/resources/revert-rename.git/config
new file mode 100644 (file)
index 0000000..a4ef456
--- /dev/null
@@ -0,0 +1,5 @@
+[core]
+       repositoryformatversion = 0
+       filemode = true
+       bare = true
+       logallrefupdates = true
diff --git a/tests/resources/revert-rename.git/index b/tests/resources/revert-rename.git/index
new file mode 100644 (file)
index 0000000..232325d
Binary files /dev/null and b/tests/resources/revert-rename.git/index differ
diff --git a/tests/resources/revert-rename.git/objects/info/packs b/tests/resources/revert-rename.git/objects/info/packs
new file mode 100644 (file)
index 0000000..5d97142
--- /dev/null
@@ -0,0 +1,2 @@
+P pack-4363774fb90141e8aa7a326ace0566366114e869.pack
+
diff --git a/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.idx b/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.idx
new file mode 100644 (file)
index 0000000..3fb48ea
Binary files /dev/null and b/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.idx differ
diff --git a/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.pack b/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.pack
new file mode 100644 (file)
index 0000000..e078ec2
Binary files /dev/null and b/tests/resources/revert-rename.git/objects/pack/pack-4363774fb90141e8aa7a326ace0566366114e869.pack differ
diff --git a/tests/resources/revert-rename.git/packed-refs b/tests/resources/revert-rename.git/packed-refs
new file mode 100644 (file)
index 0000000..e062909
--- /dev/null
@@ -0,0 +1,2 @@
+# pack-refs with: peeled fully-peeled sorted 
+ecef6a85173b6f446873a13f7b5a7b54a85cd912 refs/heads/master
diff --git a/tests/resources/revert-rename.git/refs/heads/master b/tests/resources/revert-rename.git/refs/heads/master
new file mode 100644 (file)
index 0000000..3771102
--- /dev/null
@@ -0,0 +1 @@
+ecef6a85173b6f446873a13f7b5a7b54a85cd912
diff --git a/tests/resources/self-signed.pem b/tests/resources/self-signed.pem
new file mode 100644 (file)
index 0000000..e13417e
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjsCFAb11im6DYQyGJ0GNQCIehXtegq6MA0GCSqGSIb3DQEBCwUAMGYx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlD
+YW1icmlkZ2UxEDAOBgNVBAoMB2xpYmdpdDIxGTAXBgNVBAMMEHRlc3QubGliZ2l0
+Mi5vcmcwHhcNMjEwODMwMDAyMTQyWhcNMzEwODI4MDAyMTQyWjBmMQswCQYDVQQG
+EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdl
+MRAwDgYDVQQKDAdsaWJnaXQyMRkwFwYDVQQDDBB0ZXN0LmxpYmdpdDIub3JnMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtqe6b1vnMni+z8Z+a2bGtykI
+ITvBged15rn+0qG6Fz+sn9bYG+ceFupztFfoN3cVpUgQDBTzr3CaAx036BlV0z8i
+CrG0Oh/XGL+9TITQLumEe4iGi8NoMSujBAyXPSNgmpzDmCTGrNFfmq3HzUtO8t3x
+i8OT7d9qCVjFimLvZbgnfHGQ38xvt1XyPgYIVqDQczmMEZ5BdYWB0A1VmnWuP2dH
+BgjwPEC3HwMmm1+PL0VoPTdvE5Su092Qdt8QsiA56466DQyll1d/omnOJfrK7z0N
+OnfDmnDpARSTy6vDofEAYUQoc3dyvBUk8IIzv2UDcR7fTVvYqseQReIOTEnXmQID
+AQABMA0GCSqGSIb3DQEBCwUAA4IBAQBmUEq+JhwWTbB5ODGOKrMG1fKJ+sf6ZH6M
+c4BgLEcdoi/nOTfPuw+ols72LuhH7NKaEcqxWev0jGF0WKqMcM8AGVbywZJ3mBWo
+sKdh6rAGFNkikW4TzhjtDfFbMR45Didl28Be7ieHQL4CQ0Lse3RMOxp250WpiEYV
+W2hIKMwIqOLKGShVD7lI+eHlv+QSH4yOYKHfRHve8s82Tac5OXinc8CJm9ySOtkO
+MfLgfkHtHdFBnV6OVbf4p/596MfMXdwT/bBxT6WPkDGc1AYhoDlmLFTpRgHIDCSK
+2wgV+qHppl7Kn+p3mFQ9sW/1IaRd+jNZOrgZ8Uu5tJ00OaqR/LVG
+-----END CERTIFICATE-----
diff --git a/tests/resources/testrepo.git/objects/info/commit-graph b/tests/resources/testrepo.git/objects/info/commit-graph
new file mode 100644 (file)
index 0000000..2ef31d8
Binary files /dev/null and b/tests/resources/testrepo.git/objects/info/commit-graph differ
diff --git a/tests/revert/rename.c b/tests/revert/rename.c
new file mode 100644 (file)
index 0000000..0d713c6
--- /dev/null
@@ -0,0 +1,49 @@
+#include "clar.h"
+#include "clar_libgit2.h"
+
+#include "git2/revert.h"
+#include "../merge/merge_helpers.h"
+
+#define TEST_REPO_PATH "revert-rename.git"
+
+static git_repository *repo;
+
+/* Fixture setup and teardown */
+void test_revert_rename__initialize(void)
+{
+       repo = cl_git_sandbox_init(TEST_REPO_PATH);
+}
+
+void test_revert_rename__cleanup(void)
+{
+       cl_git_sandbox_cleanup();
+}
+
+/* Attempt a revert when there is a file rename AND change of file mode,
+ * but the file contents remain the same. Check that the file mode doesn't
+ * change following the revert.
+ */
+void test_revert_rename__automerge(void)
+{
+  git_commit *head_commit, *revert_commit;
+  git_oid revert_oid;
+  git_index *index;
+  git_reference *head_ref;
+
+  struct merge_index_entry merge_index_entries[] = {
+    { 0100644, "f0f64c618e1646d2948a456ed7c4bcfad5536d68", 0, "goodmode" }};
+
+  cl_git_pass(git_repository_head(&head_ref, repo));
+  cl_git_pass(git_reference_peel((git_object **)&head_commit, head_ref, GIT_OBJECT_COMMIT));
+
+  cl_git_pass(git_oid_fromstr(&revert_oid, "7b4d7c3789b3581973c04087cb774c3c3576de2f"));
+  cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_oid));
+
+  cl_git_pass(git_revert_commit(&index, repo, revert_commit, head_commit, 0, NULL));
+  cl_assert(merge_test_index(index, merge_index_entries, 1));
+
+  git_commit_free(revert_commit);
+  git_commit_free(head_commit);
+  git_index_free(index);
+  git_reference_free(head_ref);
+}
index ee70ec635a44d072d98959b1c9c0dbbdf6e2c2ef..2c8d885e24d9f1bd5b779a3b7c817b5b8c885a64 100644 (file)
@@ -530,7 +530,7 @@ void test_revwalk_basic__big_timestamp(void)
        cl_git_pass(git_reference_peel((git_object **) &tip, head, GIT_OBJECT_COMMIT));
 
        /* Commit with a far-ahead timestamp, we should be able to parse it in the revwalk */
-       cl_git_pass(git_signature_new(&sig, "Joe", "joe@example.com", 2399662595ll, 0));
+       cl_git_pass(git_signature_new(&sig, "Joe", "joe@example.com", INT64_C(2399662595), 0));
        cl_git_pass(git_commit_tree(&tree, tip));
 
        cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1,
index bee0b926e0851bbb1d4f90061a654f4da258e231..0378c869b710751d16db104f877dd951ed32535e 100644 (file)
@@ -150,7 +150,7 @@ void test_revwalk_mergebase__multiple_merge_bases(void)
        cl_assert_equal_oid(&expected1, &result.ids[0]);
        cl_assert_equal_oid(&expected2, &result.ids[1]);
 
-       git_oidarray_free(&result);
+       git_oidarray_dispose(&result);
 }
 
 void test_revwalk_mergebase__multiple_merge_bases_many_commits(void)
@@ -170,7 +170,7 @@ void test_revwalk_mergebase__multiple_merge_bases_many_commits(void)
        cl_assert_equal_oid(&expected1, &result.ids[0]);
        cl_assert_equal_oid(&expected2, &result.ids[1]);
 
-       git_oidarray_free(&result);
+       git_oidarray_dispose(&result);
        git__free(input);
 }
 
@@ -186,7 +186,7 @@ void test_revwalk_mergebase__no_off_by_one_missing(void)
 static void assert_mergebase_many(const char *expected_sha, int count, ...)
 {
        va_list ap;
-       int i; 
+       int i;
        git_oid *oids;
        git_oid oid, expected;
        char *partial_oid;
@@ -376,9 +376,9 @@ void test_revwalk_mergebase__octopus_merge_branch(void)
  * * commit 8496071c1b46c854b31185ea97743be6a8774479
  *   Author: Scott Chacon <schacon@gmail.com>
  *   Date:   Sat May 8 16:13:06 2010 -0700
- * 
+ *
  *       testing
- * 
+ *
  * * commit 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9
  * | Author: Scott Chacon <schacon@gmail.com>
  * | Date:   Tue May 11 13:40:41 2010 -0700
@@ -388,7 +388,7 @@ void test_revwalk_mergebase__octopus_merge_branch(void)
  * * commit 5001298e0c09ad9c34e4249bc5801c75e9754fa5
  *   Author: Scott Chacon <schacon@gmail.com>
  *   Date:   Tue May 11 13:40:23 2010 -0700
- * 
+ *
  *       packed commit one
  */
 
@@ -398,94 +398,94 @@ void test_revwalk_mergebase__octopus_merge_branch(void)
  * |\  Merge: c37a783 2224e19
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:31:04 2012 -0800
- * | | 
+ * | |
  * | |     Merge branch 'first-branch' into second-branch
- * | |   
+ * | |
  * | * commit 2224e191514cb4bd8c566d80dac22dfcb1e9bb83
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:28:51 2012 -0800
- * | | 
+ * | |
  * | |     j
- * | |   
+ * | |
  * | * commit a41a49f8f5cd9b6cb14a076bf8394881ed0b4d19
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:28:39 2012 -0800
- * | | 
+ * | |
  * | |     i
- * | |   
+ * | |
  * | * commit 82bf9a1a10a4b25c1f14c9607b60970705e92545
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:28:28 2012 -0800
- * | | 
+ * | |
  * | |     h
- * | |   
+ * | |
  * * | commit c37a783c20d92ac92362a78a32860f7eebf938ef
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:30:57 2012 -0800
- * | | 
+ * | |
  * | |     n
- * | |   
+ * | |
  * * | commit 8b82fb1794cb1c8c7f172ec730a4c2db0ae3e650
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:30:43 2012 -0800
- * | | 
+ * | |
  * | |     m
- * | |   
+ * | |
  * * | commit 6ab5d28acbf3c3bdff276f7ccfdf29c1520e542f
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:30:38 2012 -0800
- * | | 
+ * | |
  * | |     l
- * | |   
+ * | |
  * * | commit 7b8c336c45fc6895c1c60827260fe5d798e5d247
  * | | Author: Scott J. Goldman <scottjg@github.com>
  * | | Date:   Tue Nov 27 20:30:24 2012 -0800
- * | | 
+ * | |
  * | |     k
- * | |     
+ * | |
  * | | * commit 1c30b88f5f3ee66d78df6520a7de9e89b890818b
  * | | | Author: Scott J. Goldman <scottjg@github.com>
  * | | | Date:   Tue Nov 27 20:28:10 2012 -0800
- * | | | 
+ * | | |
  * | | |     e
- * | | |    
+ * | | |
  * | | * commit 42b7311aa626e712891940c1ec5d5cba201946a4
  * | | | Author: Scott J. Goldman <scottjg@github.com>
  * | | | Date:   Tue Nov 27 20:28:06 2012 -0800
- * | | | 
+ * | | |
  * | | |     d
- * | | |      
+ * | | |
  * | | *   commit a953a018c5b10b20c86e69fef55ebc8ad4c5a417
  * | | |\  Merge: bd1732c cdf97fd
  * | | |/  Author: Scott J. Goldman <scottjg@github.com>
  * | |/|   Date:   Tue Nov 27 20:26:43 2012 -0800
- * | | |   
+ * | | |
  * | | |       Merge branch 'first-branch'
- * | | |    
+ * | | |
  * | * | commit cdf97fd3bb48eb3827638bb33d208f5fd32d0aa6
  * | | | Author: Scott J. Goldman <scottjg@github.com>
  * | | | Date:   Tue Nov 27 20:24:46 2012 -0800
- * | | | 
+ * | | |
  * | | |     g
- * | | |    
+ * | | |
  * | * | commit ef0488f0b722f0be8bcb90a7730ac7efafd1d694
  * | | | Author: Scott J. Goldman <scottjg@github.com>
  * | | | Date:   Tue Nov 27 20:24:39 2012 -0800
- * | | | 
+ * | | |
  * | | |     f
- * | | |    
+ * | | |
  * | | * commit bd1732c43c68d712ad09e1d872b9be6d4b9efdc4
  * | |/  Author: Scott J. Goldman <scottjg@github.com>
  * | |   Date:   Tue Nov 27 17:43:58 2012 -0800
- * | |   
+ * | |
  * | |       c
- * | |   
+ * | |
  * | * commit 0c8a3f1f3d5f421cf83048c7c73ee3b55a5e0f29
  * |/  Author: Scott J. Goldman <scottjg@github.com>
  * |   Date:   Tue Nov 27 17:43:48 2012 -0800
- * |   
+ * |
  * |       b
- * |  
+ * |
  * * commit 1f4c0311a24b63f6fc209a59a1e404942d4a5006
  *   Author: Scott J. Goldman <scottjg@github.com>
  *   Date:   Tue Nov 27 17:43:41 2012 -0800
@@ -509,6 +509,6 @@ void test_revwalk_mergebase__remove_redundant(void)
        cl_assert_equal_i(1, result.count);
        cl_assert_equal_oid(&base, &result.ids[0]);
 
-       git_oidarray_free(&result);
+       git_oidarray_dispose(&result);
        git_repository_free(repo);
 }
index d2842485b4864ab376fac75c92ee96bb342e8b8f..d9fce44046a7bd247351b18ebceb310a50f7ab50 100644 (file)
@@ -605,6 +605,45 @@ void test_status_worktree__filemode_changes(void)
        cl_assert_equal_i(0, counts.wrong_sorted_path);
 }
 
+void test_status_worktree__filemode_non755(void)
+{
+       git_repository *repo = cl_git_sandbox_init("filemodes");
+       status_entry_counts counts;
+       git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+       git_buf executable_path = GIT_BUF_INIT;
+       git_buf nonexecutable_path = GIT_BUF_INIT;
+
+       if (!cl_is_chmod_supported())
+               return;
+
+       opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
+               GIT_STATUS_OPT_INCLUDE_IGNORED |
+               GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
+
+       git_buf_joinpath(&executable_path, git_repository_workdir(repo), "exec_on");
+       cl_must_pass(p_chmod(git_buf_cstr(&executable_path), 0744));
+       git_buf_dispose(&executable_path);
+
+       git_buf_joinpath(&nonexecutable_path, git_repository_workdir(repo), "exec_off");
+
+       cl_must_pass(p_chmod(git_buf_cstr(&nonexecutable_path), 0655));
+       git_buf_dispose(&nonexecutable_path);
+
+       memset(&counts, 0, sizeof(counts));
+       counts.expected_entry_count = filemode_count;
+       counts.expected_paths = filemode_paths;
+       counts.expected_statuses = filemode_statuses;
+
+       cl_git_pass(
+               git_status_foreach_ext(repo, &opts, cb_status__normal, &counts)
+       );
+
+       cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+       cl_assert_equal_i(0, counts.wrong_status_flags_count);
+       cl_assert_equal_i(0, counts.wrong_sorted_path);
+}
+
+
 static int cb_status__interrupt(const char *p, unsigned int s, void *payload)
 {
        volatile int *count = (int *)payload;
index 6f7506d2ce5e9f62dfaf2e0ef88131b91ce2c9af..f49ebb4bdc60b4eec16844c4516120329125a1a4 100644 (file)
@@ -42,6 +42,46 @@ void test_submodule_lookup__simple_lookup(void)
        assert_submodule_exists(g_repo, "sm_added_and_uncommited/");
 }
 
+void test_submodule_lookup__can_be_dupped(void)
+{
+       git_submodule *sm;
+       git_submodule *sm_duplicate;
+       const char *oid = "480095882d281ed676fe5b863569520e54a7d5c0";
+
+       /* Check original */
+       cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+       cl_assert(git_submodule_owner(sm) == g_repo);
+       cl_assert_equal_s("sm_unchanged", git_submodule_name(sm));
+       cl_assert(git__suffixcmp(git_submodule_path(sm), "sm_unchanged") == 0);
+       cl_assert(git__suffixcmp(git_submodule_url(sm), "/submod2_target") == 0);
+
+       cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0);
+       cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0);
+       cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0);
+
+       cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE);
+       cl_assert(git_submodule_update_strategy(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
+
+       /* Duplicate and free original */
+       cl_assert(git_submodule_dup(&sm_duplicate, sm) == 0);
+       git_submodule_free(sm);
+
+       /* Check duplicate */
+       cl_assert(git_submodule_owner(sm_duplicate) == g_repo);
+       cl_assert_equal_s("sm_unchanged", git_submodule_name(sm_duplicate));
+       cl_assert(git__suffixcmp(git_submodule_path(sm_duplicate), "sm_unchanged") == 0);
+       cl_assert(git__suffixcmp(git_submodule_url(sm_duplicate), "/submod2_target") == 0);
+
+       cl_assert(git_oid_streq(git_submodule_index_id(sm_duplicate), oid) == 0);
+       cl_assert(git_oid_streq(git_submodule_head_id(sm_duplicate), oid) == 0);
+       cl_assert(git_oid_streq(git_submodule_wd_id(sm_duplicate), oid) == 0);
+
+       cl_assert(git_submodule_ignore(sm_duplicate) == GIT_SUBMODULE_IGNORE_NONE);
+       cl_assert(git_submodule_update_strategy(sm_duplicate) == GIT_SUBMODULE_UPDATE_CHECKOUT);
+
+       git_submodule_free(sm_duplicate);
+}
+
 void test_submodule_lookup__accessors(void)
 {
        git_submodule *sm;
diff --git a/tests/threads/atomic.c b/tests/threads/atomic.c
new file mode 100644 (file)
index 0000000..4d04a77
--- /dev/null
@@ -0,0 +1,125 @@
+#include "clar_libgit2.h"
+
+void test_threads_atomic__atomic32_set(void)
+{
+       git_atomic32 v = {0};
+       git_atomic32_set(&v, 1);
+       cl_assert_equal_i(v.val, 1);
+}
+
+void test_threads_atomic__atomic32_get(void)
+{
+       git_atomic32 v = {1};
+       cl_assert_equal_i(git_atomic32_get(&v), 1);
+}
+
+void test_threads_atomic__atomic32_inc(void)
+{
+       git_atomic32 v = {0};
+       cl_assert_equal_i(git_atomic32_inc(&v), 1);
+       cl_assert_equal_i(v.val, 1);
+}
+
+void test_threads_atomic__atomic32_add(void)
+{
+       git_atomic32 v = {0};
+       cl_assert_equal_i(git_atomic32_add(&v, 1), 1);
+       cl_assert_equal_i(v.val, 1);
+}
+
+void test_threads_atomic__atomic32_dec(void)
+{
+       git_atomic32 v = {1};
+       cl_assert_equal_i(git_atomic32_dec(&v), 0);
+       cl_assert_equal_i(v.val, 0);
+}
+
+void test_threads_atomic__atomic64_set(void)
+{
+#ifndef GIT_ARCH_64
+       cl_skip();
+#else
+       git_atomic64 v = {0};
+       git_atomic64_set(&v, 1);
+       cl_assert_equal_i(v.val, 1);
+#endif
+}
+
+void test_threads_atomic__atomic64_get(void)
+{
+#ifndef GIT_ARCH_64
+       cl_skip();
+#else
+       git_atomic64 v = {1};
+       cl_assert_equal_i(git_atomic64_get(&v), 1);
+#endif
+}
+
+void test_threads_atomic__atomic64_add(void)
+{
+#ifndef GIT_ARCH_64
+       cl_skip();
+#else
+       git_atomic64 v = {0};
+       cl_assert_equal_i(git_atomic64_add(&v, 1), 1);
+       cl_assert_equal_i(v.val, 1);
+#endif
+}
+
+void test_threads_atomic__cas_pointer(void)
+{
+       int *value = NULL;
+       int newvalue1 = 1, newvalue2 = 2;
+
+       /* value is updated */
+       cl_assert_equal_p(git_atomic_compare_and_swap(&value, NULL, &newvalue1), NULL);
+       cl_assert_equal_p(value, &newvalue1);
+
+       /* value is not updated */
+       cl_assert_equal_p(git_atomic_compare_and_swap(&value, NULL, &newvalue2), &newvalue1);
+       cl_assert_equal_p(value, &newvalue1);
+}
+
+void test_threads_atomic__cas_intptr(void)
+{
+       intptr_t value = 0;
+       intptr_t oldvalue;
+       intptr_t newvalue;
+
+       /* value is updated */
+       oldvalue = 0;
+       newvalue = 1;
+       cl_assert_equal_i((intptr_t)git_atomic_compare_and_swap(&value, (void *)oldvalue, (void *)newvalue), 0);
+       cl_assert_equal_i(value, 1);
+
+       /* value is not updated */
+       oldvalue = 0;
+       newvalue = 2;
+       cl_assert_equal_i((intptr_t)git_atomic_compare_and_swap(&value, (void *)oldvalue, (void *)newvalue), 1);
+       cl_assert_equal_i(value, 1);
+}
+
+void test_threads_atomic__swap(void)
+{
+       int *value = NULL;
+       int newvalue = 1;
+
+       cl_assert_equal_p(git_atomic_swap(value, &newvalue), NULL);
+       cl_assert_equal_p(value, &newvalue);
+
+       cl_assert_equal_p(git_atomic_swap(value, NULL), &newvalue);
+       cl_assert_equal_p(value, NULL);
+}
+
+void test_threads_atomic__load_ptr(void)
+{
+       int value = 1;
+       int *ptr = &value;
+       cl_assert_equal_p(git_atomic_load(ptr), &value);
+}
+
+void test_threads_atomic__load_intptr(void)
+{
+       intptr_t value = 1;
+       cl_assert_equal_i((intptr_t)git_atomic_load(value), 1);
+}
index ed4fd2f9b9d0907cb51ec459e7af989099b81573..2d7ddc26b99d0699527302d6856b116edef4541f 100644 (file)
@@ -54,6 +54,12 @@ static void *return_normally(void *param)
 {
        return param;
 }
+
+static void *exit_abruptly(void *param)
+{
+       git_thread_exit(param);
+       return NULL;
+}
 #endif
 
 void test_threads_basic__exit(void)
@@ -70,7 +76,7 @@ void test_threads_basic__exit(void)
        cl_assert_equal_sz(424242, (size_t)result);
 
        /* Ensure that the return value of `git_thread_exit` is returned. */
-       cl_git_pass(git_thread_create(&thread, return_normally, (void *)232323));
+       cl_git_pass(git_thread_create(&thread, exit_abruptly, (void *)232323));
        cl_git_pass(git_thread_join(&thread, &result));
        cl_assert_equal_sz(232323, (size_t)result);
 #endif
index 699642790010e68f7c4f61305356c4b541db35f8..04c8cb97fd3151253d99a374174da6b418d46533 100644 (file)
@@ -17,7 +17,7 @@
 
 static git_repository *_repo;
 static git_tree *_a, *_b;
-static git_atomic _counts[4];
+static git_atomic32 _counts[4];
 static int _check_counts;
 #ifdef GIT_WIN32
 static int _retries;
@@ -66,10 +66,10 @@ static void free_trees(void)
        git_tree_free(_b); _b = NULL;
 
        if (_check_counts) {
-               cl_assert_equal_i(288, git_atomic_get(&_counts[0]));
-               cl_assert_equal_i(112, git_atomic_get(&_counts[1]));
-               cl_assert_equal_i( 80, git_atomic_get(&_counts[2]));
-               cl_assert_equal_i( 96, git_atomic_get(&_counts[3]));
+               cl_assert_equal_i(288, git_atomic32_get(&_counts[0]));
+               cl_assert_equal_i(112, git_atomic32_get(&_counts[1]));
+               cl_assert_equal_i( 80, git_atomic32_get(&_counts[2]));
+               cl_assert_equal_i( 96, git_atomic32_get(&_counts[3]));
        }
 }
 
@@ -107,14 +107,14 @@ static void *run_index_diffs(void *arg)
        /* keep some diff stats to make sure results are as expected */
 
        i = git_diff_num_deltas(diff);
-       git_atomic_add(&_counts[0], (int32_t)i);
+       git_atomic32_add(&_counts[0], (int32_t)i);
        exp[0] = (int)i;
 
        while (i > 0) {
                switch (git_diff_get_delta(diff, --i)->status) {
-               case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break;
-               case GIT_DELTA_ADDED:    exp[2]++; git_atomic_inc(&_counts[2]); break;
-               case GIT_DELTA_DELETED:  exp[3]++; git_atomic_inc(&_counts[3]); break;
+               case GIT_DELTA_MODIFIED: exp[1]++; git_atomic32_inc(&_counts[1]); break;
+               case GIT_DELTA_ADDED:    exp[2]++; git_atomic32_inc(&_counts[2]); break;
+               case GIT_DELTA_DELETED:  exp[3]++; git_atomic32_inc(&_counts[3]); break;
                default: break;
                }
        }
index 3c13cfb6bb44f9f0532397a1eb7b0570f73025c8..0f23a4ce06d3c60b2ef88fa6aaa7b38c5937a334 100644 (file)
@@ -1,4 +1,4 @@
-#include "thread-utils.h"
+#include "thread.h"
 
 void run_in_parallel(
        int repeats,
diff --git a/tests/threads/tlsdata.c b/tests/threads/tlsdata.c
new file mode 100644 (file)
index 0000000..7c69b44
--- /dev/null
@@ -0,0 +1,65 @@
+#include "clar_libgit2.h"
+
+#include "thread_helpers.h"
+
+void test_threads_tlsdata__can_set_and_get(void)
+{
+       git_tlsdata_key key_one, key_two, key_three;
+
+       cl_git_pass(git_tlsdata_init(&key_one, NULL));
+       cl_git_pass(git_tlsdata_init(&key_two, NULL));
+       cl_git_pass(git_tlsdata_init(&key_three, NULL));
+
+       cl_git_pass(git_tlsdata_set(key_one, (void *)(size_t)42424242));
+       cl_git_pass(git_tlsdata_set(key_two, (void *)(size_t)0xdeadbeef));
+       cl_git_pass(git_tlsdata_set(key_three, (void *)(size_t)98761234));
+
+       cl_assert_equal_sz((size_t)42424242, git_tlsdata_get(key_one));
+       cl_assert_equal_sz((size_t)0xdeadbeef, git_tlsdata_get(key_two));
+       cl_assert_equal_sz((size_t)98761234, git_tlsdata_get(key_three));
+
+       cl_git_pass(git_tlsdata_dispose(key_one));
+       cl_git_pass(git_tlsdata_dispose(key_two));
+       cl_git_pass(git_tlsdata_dispose(key_three));
+}
+
+#ifdef GIT_THREADS
+
+static void *set_and_get(void *param)
+{
+       git_tlsdata_key *tlsdata_key = (git_tlsdata_key *)param;
+       int val;
+
+       if (git_tlsdata_set(*tlsdata_key, &val) != 0 ||
+           git_tlsdata_get(*tlsdata_key) != &val)
+               return (void *)0;
+
+       return (void *)1;
+}
+
+#endif
+
+#define THREAD_COUNT 10
+
+void test_threads_tlsdata__threads(void)
+{
+#ifdef GIT_THREADS
+       git_thread thread[THREAD_COUNT];
+       git_tlsdata_key tlsdata;
+       int i;
+
+       cl_git_pass(git_tlsdata_init(&tlsdata, NULL));
+
+       for (i = 0; i < THREAD_COUNT; i++)
+               cl_git_pass(git_thread_create(&thread[i], set_and_get, &tlsdata));
+
+       for (i = 0; i < THREAD_COUNT; i++) {
+               void *result;
+
+               cl_git_pass(git_thread_join(&thread[i], &result));
+               cl_assert_equal_sz(1, (size_t)result);
+       }
+
+       cl_git_pass(git_tlsdata_dispose(tlsdata));
+#endif
+}
index 756ac68a398fbfc2840407cafff74e1489b0b9f2..0a77ef99d212ff00c1ce24334e00a32e9c7f3979 100644 (file)
@@ -1,13 +1,12 @@
 #include "clar_libgit2.h"
-#include "win32/w32_stack.h"
-#include "win32/w32_crtdbg_stacktrace.h"
+#include "win32/w32_leakcheck.h"
 
-#if defined(GIT_MSVC_CRTDBG)
+#if defined(GIT_WIN32_LEAKCHECK)
 static void a(void)
 {
        char buf[10000];
 
-       cl_assert(git_win32__stack(buf, sizeof(buf), 0, NULL, NULL) == 0);
+       cl_assert(git_win32_leakcheck_stack(buf, sizeof(buf), 0, NULL, NULL) == 0);
 
 #if 0
        fprintf(stderr, "Stacktrace from [%s:%d]:\n%s\n", __FILE__, __LINE__, buf);
@@ -27,7 +26,7 @@ static void c(void)
 
 void test_trace_windows_stacktrace__basic(void)
 {
-#if defined(GIT_MSVC_CRTDBG)
+#if defined(GIT_WIN32_LEAKCHECK)
        c();
 #endif
 }
@@ -35,7 +34,7 @@ void test_trace_windows_stacktrace__basic(void)
 
 void test_trace_windows_stacktrace__leaks(void)
 {
-#if defined(GIT_MSVC_CRTDBG)
+#if defined(GIT_WIN32_LEAKCHECK)
        void * p1;
        void * p2;
        void * p3;
@@ -47,84 +46,85 @@ void test_trace_windows_stacktrace__leaks(void)
        /* remember outstanding leaks due to set setup
         * and set mark/checkpoint.
         */
-       before = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL |
-               GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
+       before = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_TOTAL |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_SET_MARK,
                NULL);
 
        p1 = git__malloc(5);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p1");
-       cl_assert((leaks == 1));
+       cl_assert_equal_i(1, leaks);
 
        p2 = git__malloc(5);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p1,p2");
-       cl_assert((leaks == 2));
+       cl_assert_equal_i(2, leaks);
 
        p3 = git__malloc(5);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p1,p2,p3");
-       cl_assert((leaks == 3));
+       cl_assert_equal_i(3, leaks);
 
        git__free(p2);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p1,p3");
-       cl_assert((leaks == 2));
+       cl_assert_equal_i(2, leaks);
 
        /* move the mark. only new leaks should appear afterwards */
-       error = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
+       error = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_SET_MARK,
                NULL);
-       cl_assert((error == 0));
+       /* cannot use cl_git_pass() since that may allocate memory. */
+       cl_assert_equal_i(0, error);
 
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "not_p1,not_p3");
-       cl_assert((leaks == 0));
+       cl_assert_equal_i(0, leaks);
 
        p4 = git__malloc(5);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p4,not_p1,not_p3");
-       cl_assert((leaks == 1));
+       cl_assert_equal_i(1, leaks);
 
        git__free(p1);
        git__free(p3);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "p4");
-       cl_assert((leaks == 1));
+       cl_assert_equal_i(1, leaks);
 
        git__free(p4);
-       leaks = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
+       leaks = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_SINCE_MARK,
                "end");
-       cl_assert((leaks == 0));
+       cl_assert_equal_i(0, leaks);
 
        /* confirm current absolute leaks count matches beginning value. */
-       after = git_win32__crtdbg_stacktrace__dump(
-               GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
-               GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL,
+       after = git_win32_leakcheck_stacktrace_dump(
+               GIT_WIN32_LEAKCHECK_STACKTRACE_QUIET |
+               GIT_WIN32_LEAKCHECK_STACKTRACE_LEAKS_TOTAL,
                "total");
-       cl_assert((before == after));
+       cl_assert_equal_i(before, after);
 #endif
 }
 
-#if defined(GIT_MSVC_CRTDBG)
+#if defined(GIT_WIN32_LEAKCHECK)
 static void aux_cb_alloc__1(unsigned int *aux_id)
 {
        static unsigned int aux_counter = 0;
@@ -141,12 +141,12 @@ static void aux_cb_lookup__1(unsigned int aux_id, char *aux_msg, size_t aux_msg_
 
 void test_trace_windows_stacktrace__aux1(void)
 {
-#if defined(GIT_MSVC_CRTDBG)
-       git_win32__stack__set_aux_cb(aux_cb_alloc__1, aux_cb_lookup__1);
+#if defined(GIT_WIN32_LEAKCHECK)
+       git_win32_leakcheck_stack_set_aux_cb(aux_cb_alloc__1, aux_cb_lookup__1);
        c();
        c();
        c();
        c();
-       git_win32__stack__set_aux_cb(NULL, NULL);
+       git_win32_leakcheck_stack_set_aux_cb(NULL, NULL);
 #endif
 }
index 80ae08d8bbdb385d91f1e62ee211fe7434611bc2..f8b8c4b0ae89e2e16ef5646ae617e6f0ad49b1aa 100644 (file)
@@ -4,9 +4,12 @@
 #include "clone.h"
 #include "buffer.h"
 #include "futils.h"
+#include "repository.h"
 
 static git_buf path = GIT_BUF_INIT;
 
+#define LONG_FILENAME "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt"
+
 void test_win32_longpath__initialize(void)
 {
 #ifdef GIT_WIN32
@@ -29,34 +32,100 @@ void test_win32_longpath__initialize(void)
 void test_win32_longpath__cleanup(void)
 {
        git_buf_dispose(&path);
+       cl_git_sandbox_cleanup();
 }
 
+void test_win32_longpath__errmsg_on_checkout(void)
+{
 #ifdef GIT_WIN32
-void assert_name_too_long(void)
+       git_repository *repo;
+
+       cl_git_fail(git_clone(&repo, cl_fixture("testrepo.git"), path.ptr, NULL));
+       cl_assert(git__prefixcmp(git_error_last()->message, "path too long") == 0);
+#endif
+}
+
+void test_win32_longpath__workdir_path_validated(void)
 {
-       const git_error *err;
-       size_t expected_len, actual_len;
-       char *expected_msg;
+#ifdef GIT_WIN32
+       git_repository *repo = cl_git_sandbox_init("testrepo");
+       git_buf out = GIT_BUF_INIT;
+
+       cl_git_pass(git_repository_workdir_path(&out, repo, "a.txt"));
+
+       /* even if the repo path is a drive letter, this is too long */
+       cl_git_fail(git_repository_workdir_path(&out, repo, LONG_FILENAME));
+       cl_assert(git__prefixcmp(git_error_last()->message, "path too long") == 0);
 
-       err = git_error_last();
-       actual_len = strlen(err->message);
+       cl_repo_set_bool(repo, "core.longpaths", true);
+       cl_git_pass(git_repository_workdir_path(&out, repo, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt"));
+       cl_git_pass(git_repository_workdir_path(&out, repo, LONG_FILENAME));
+       git_buf_dispose(&out);
+#endif
+}
+
+#ifdef GIT_WIN32
+static void assert_longpath_status_and_add(git_repository *repo, const char *wddata, const char *repodata) {
+       git_index *index;
+       git_blob *blob;
+       git_buf out = GIT_BUF_INIT;
+       const git_index_entry *entry;
+       unsigned int status_flags;
 
-       expected_msg = git_win32_get_error_message(ERROR_FILENAME_EXCED_RANGE);
-       expected_len = strlen(expected_msg);
+       cl_git_pass(git_repository_workdir_path(&out, repo, LONG_FILENAME));
 
-       /* check the suffix */
-       cl_assert_equal_s(expected_msg, err->message + (actual_len - expected_len));
+       cl_git_rewritefile(out.ptr, wddata);
 
-       git__free(expected_msg);
+       cl_git_pass(git_status_file(&status_flags, repo, LONG_FILENAME));
+       cl_assert_equal_i(GIT_STATUS_WT_NEW, status_flags);
+
+       cl_git_pass(git_repository_index(&index, repo));
+       cl_git_pass(git_index_add_bypath(index, LONG_FILENAME));
+
+       cl_git_pass(git_status_file(&status_flags, repo, LONG_FILENAME));
+       cl_assert_equal_i(GIT_STATUS_INDEX_NEW, status_flags);
+
+       cl_assert((entry = git_index_get_bypath(index, LONG_FILENAME, 0)) != NULL);
+       cl_git_pass(git_blob_lookup(&blob, repo, &entry->id));
+       cl_assert_equal_s(repodata, git_blob_rawcontent(blob));
+
+       git_blob_free(blob);
+       git_index_free(index);
+       git_buf_dispose(&out);
 }
 #endif
 
-void test_win32_longpath__errmsg_on_checkout(void)
+void test_win32_longpath__status_and_add(void)
 {
 #ifdef GIT_WIN32
-       git_repository *repo;
+       git_repository *repo = cl_git_sandbox_init("testrepo");
 
-       cl_git_fail(git_clone(&repo, cl_fixture("testrepo.git"), path.ptr, NULL));
-       assert_name_too_long();
+       cl_repo_set_bool(repo, "core.longpaths", true);
+
+       /*
+        * Doing no content filtering, we expect the data we add
+        * to be the data in the repository.
+        */
+       assert_longpath_status_and_add(repo,
+           "This is a long path.\r\n",
+           "This is a long path.\r\n");
+#endif
+}
+
+void test_win32_longpath__status_and_add_with_filter(void)
+{
+#ifdef GIT_WIN32
+       git_repository *repo = cl_git_sandbox_init("testrepo");
+
+       cl_repo_set_bool(repo, "core.longpaths", true);
+       cl_repo_set_bool(repo, "core.autocrlf", true);
+
+       /*
+        * With `core.autocrlf`, we expect the data we add to have
+        * newline conversion performed.
+        */
+       assert_longpath_status_and_add(repo,
+           "This is a long path.\r\n",
+           "This is a long path.\n");
 #endif
 }
index 4b743829cd80639a605a6645dd6077e6a64cc4a4..2a1206032c880b3e6f4b0e58ebb643ba200858ee 100644 (file)
@@ -70,9 +70,9 @@ void test_worktree_merge__merge_setup(void)
                    ours, (const git_annotated_commit **)&theirs, 1));
 
        for (i = 0; i < ARRAY_SIZE(merge_files); i++) {
-               git_buf_clear(&path);
-               cl_git_pass(git_buf_printf(&path, "%s/%s",
-                           fixture.worktree->gitdir, merge_files[i]));
+               cl_git_pass(git_buf_joinpath(&path,
+                           fixture.worktree->gitdir,
+                           merge_files[i]));
                cl_assert(git_path_exists(path.ptr));
        }
 
index cd20bed82fa19ae10272248b2f8debac17ba6082..9b87bfae64f717fc7f6418728d4012383a0952eb 100644 (file)
@@ -44,8 +44,9 @@ void test_worktree_worktree__list_with_invalid_worktree_dirs(void)
        git_strarray wts;
        size_t i, j, len;
 
-       cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid",
-                   fixture.repo->commondir));
+       cl_git_pass(git_buf_joinpath(&path,
+                   fixture.repo->commondir,
+                   "worktrees/invalid"));
        cl_git_pass(p_mkdir(path.ptr, 0755));
 
        len = path.size;
@@ -145,9 +146,9 @@ void test_worktree_worktree__open_invalid_commondir(void)
        git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
 
        cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/commondir"));
-       cl_git_pass(git_buf_printf(&path,
-                   "%s/worktrees/testrepo-worktree/commondir",
-                   fixture.repo->commondir));
+       cl_git_pass(git_buf_joinpath(&path,
+                   fixture.repo->commondir,
+                   "worktrees/testrepo-worktree/commondir"));
        cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
 
        cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
@@ -165,9 +166,9 @@ void test_worktree_worktree__open_invalid_gitdir(void)
        git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
 
        cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir"));
-       cl_git_pass(git_buf_printf(&path,
-                   "%s/worktrees/testrepo-worktree/gitdir",
-                   fixture.repo->commondir));
+       cl_git_pass(git_buf_joinpath(&path,
+                   fixture.repo->commondir,
+                   "worktrees/testrepo-worktree/gitdir"));
        cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
 
        cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
@@ -610,3 +611,15 @@ void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void)
        int counter = 0;
        cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter));
 }
+
+void test_worktree_worktree__validate_invalid_worktreedir(void)
+{
+       git_worktree *wt;
+
+       cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+       p_rename("testrepo-worktree", "testrepo-worktree-tmp");
+       cl_git_fail(git_worktree_validate(wt));
+       p_rename("testrepo-worktree-tmp", "testrepo-worktree");
+
+       git_worktree_free(wt);
+}