rugged 0.19.0 → 0.28.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +184 -33
- data/ext/rugged/extconf.rb +111 -28
- data/ext/rugged/rugged.c +327 -89
- data/ext/rugged/rugged.h +64 -28
- data/ext/rugged/rugged_allocator.c +89 -0
- data/ext/rugged/rugged_backend.c +17 -0
- data/ext/rugged/rugged_blame.c +278 -0
- data/ext/rugged/rugged_blob.c +301 -75
- data/ext/rugged/rugged_branch.c +92 -242
- data/ext/rugged/rugged_branch_collection.c +388 -0
- data/ext/rugged/rugged_commit.c +575 -79
- data/ext/rugged/rugged_config.c +129 -36
- data/ext/rugged/rugged_cred.c +131 -0
- data/ext/rugged/rugged_diff.c +291 -122
- data/ext/rugged/rugged_diff_delta.c +16 -22
- data/ext/rugged/rugged_diff_hunk.c +35 -51
- data/ext/rugged/rugged_diff_line.c +23 -36
- data/ext/rugged/rugged_index.c +289 -152
- data/ext/rugged/rugged_note.c +50 -60
- data/ext/rugged/rugged_object.c +13 -30
- data/ext/rugged/rugged_patch.c +400 -0
- data/ext/rugged/rugged_rebase.c +397 -0
- data/ext/rugged/rugged_reference.c +76 -346
- data/ext/rugged/rugged_reference_collection.c +423 -0
- data/ext/rugged/rugged_remote.c +438 -461
- data/ext/rugged/rugged_remote_collection.c +435 -0
- data/ext/rugged/rugged_repo.c +1548 -365
- data/ext/rugged/rugged_revwalk.c +378 -99
- data/ext/rugged/rugged_settings.c +86 -23
- data/ext/rugged/rugged_signature.c +47 -37
- data/ext/rugged/rugged_submodule.c +835 -0
- data/ext/rugged/rugged_submodule_collection.c +366 -0
- data/ext/rugged/rugged_tag.c +88 -210
- data/ext/rugged/rugged_tag_collection.c +326 -0
- data/ext/rugged/rugged_tree.c +460 -217
- data/lib/rugged/attributes.rb +46 -0
- data/lib/rugged/blob.rb +33 -0
- data/lib/rugged/branch.rb +12 -16
- data/lib/rugged/commit.rb +9 -0
- data/lib/rugged/console.rb +5 -0
- data/lib/rugged/credentials.rb +48 -0
- data/lib/rugged/diff/delta.rb +6 -2
- data/lib/rugged/diff/hunk.rb +9 -9
- data/lib/rugged/diff/line.rb +28 -5
- data/lib/rugged/diff.rb +7 -1
- data/lib/rugged/index.rb +120 -0
- data/lib/rugged/object.rb +5 -0
- data/lib/rugged/patch.rb +41 -0
- data/lib/rugged/reference.rb +6 -3
- data/lib/rugged/remote.rb +5 -9
- data/lib/rugged/repository.rb +126 -14
- data/lib/rugged/submodule_collection.rb +53 -0
- data/lib/rugged/tag.rb +45 -16
- data/lib/rugged/tree.rb +163 -1
- data/lib/rugged/version.rb +6 -1
- data/lib/rugged/walker.rb +5 -0
- data/lib/rugged.rb +16 -1
- data/vendor/libgit2/AUTHORS +77 -0
- data/vendor/libgit2/CMakeLists.txt +317 -0
- data/vendor/libgit2/COPYING +993 -0
- data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +30 -0
- data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +29 -0
- data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +96 -0
- data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +11 -0
- data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +26 -0
- data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
- data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
- data/vendor/libgit2/cmake/Modules/FindIconv.cmake +45 -0
- data/vendor/libgit2/cmake/Modules/FindPkgLibraries.cmake +28 -0
- data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +28 -0
- data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
- data/vendor/libgit2/cmake/Modules/FindmbedTLS.cmake +93 -0
- data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
- data/vendor/libgit2/deps/http-parser/CMakeLists.txt +5 -0
- data/vendor/libgit2/deps/http-parser/COPYING +23 -0
- data/vendor/libgit2/deps/http-parser/http_parser.c +5 -2
- data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
- data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
- data/vendor/libgit2/deps/regex/COPYING +502 -0
- data/vendor/libgit2/deps/regex/regex.c +10 -3
- data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
- data/vendor/libgit2/deps/winhttp/COPYING.GPL +993 -0
- data/vendor/libgit2/deps/winhttp/COPYING.LGPL +502 -0
- data/vendor/libgit2/deps/winhttp/urlmon.h +45 -0
- data/vendor/libgit2/deps/winhttp/winhttp.def +29 -0
- data/vendor/libgit2/deps/winhttp/winhttp.h +594 -0
- data/vendor/libgit2/deps/winhttp/winhttp64.def +29 -0
- data/vendor/libgit2/deps/zlib/CMakeLists.txt +5 -0
- data/vendor/libgit2/deps/zlib/COPYING +27 -0
- data/vendor/libgit2/deps/zlib/adler32.c +51 -34
- data/vendor/libgit2/deps/zlib/crc32.c +61 -61
- data/vendor/libgit2/deps/zlib/crc32.h +1 -1
- data/vendor/libgit2/deps/zlib/deflate.c +681 -352
- data/vendor/libgit2/deps/zlib/deflate.h +25 -18
- data/vendor/libgit2/deps/zlib/gzguts.h +218 -0
- data/vendor/libgit2/deps/zlib/infback.c +640 -0
- data/vendor/libgit2/deps/zlib/inffast.c +36 -53
- data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
- data/vendor/libgit2/deps/zlib/inflate.c +167 -86
- data/vendor/libgit2/deps/zlib/inflate.h +7 -4
- data/vendor/libgit2/deps/zlib/inftrees.c +24 -50
- data/vendor/libgit2/deps/zlib/trees.c +55 -96
- data/vendor/libgit2/deps/zlib/zconf.h +499 -19
- data/vendor/libgit2/deps/zlib/zlib.h +526 -227
- data/vendor/libgit2/deps/zlib/zutil.c +39 -32
- data/vendor/libgit2/deps/zlib/zutil.h +75 -78
- data/vendor/libgit2/include/git2/annotated_commit.h +125 -0
- data/vendor/libgit2/include/git2/apply.h +129 -0
- data/vendor/libgit2/include/git2/attr.h +36 -21
- data/vendor/libgit2/include/git2/blame.h +229 -0
- data/vendor/libgit2/include/git2/blob.h +81 -44
- data/vendor/libgit2/include/git2/branch.h +81 -42
- data/vendor/libgit2/include/git2/buffer.h +128 -0
- data/vendor/libgit2/include/git2/checkout.h +141 -67
- data/vendor/libgit2/include/git2/cherrypick.h +92 -0
- data/vendor/libgit2/include/git2/clone.h +157 -58
- data/vendor/libgit2/include/git2/commit.h +231 -12
- data/vendor/libgit2/include/git2/common.h +216 -30
- data/vendor/libgit2/include/git2/config.h +274 -48
- data/vendor/libgit2/include/git2/cred_helpers.h +4 -4
- data/vendor/libgit2/include/git2/deprecated.h +253 -0
- data/vendor/libgit2/include/git2/describe.h +189 -0
- data/vendor/libgit2/include/git2/diff.h +985 -575
- data/vendor/libgit2/include/git2/errors.h +93 -52
- data/vendor/libgit2/include/git2/filter.h +217 -0
- data/vendor/libgit2/include/git2/global.h +44 -0
- data/vendor/libgit2/include/git2/graph.h +17 -0
- data/vendor/libgit2/include/git2/ignore.h +2 -2
- data/vendor/libgit2/include/git2/index.h +269 -94
- data/vendor/libgit2/include/git2/indexer.h +44 -12
- data/vendor/libgit2/include/git2/mailmap.h +115 -0
- data/vendor/libgit2/include/git2/merge.h +501 -64
- data/vendor/libgit2/include/git2/message.h +52 -17
- data/vendor/libgit2/include/git2/net.h +11 -5
- data/vendor/libgit2/include/git2/notes.h +120 -16
- data/vendor/libgit2/include/git2/object.h +62 -23
- data/vendor/libgit2/include/git2/odb.h +140 -24
- data/vendor/libgit2/include/git2/odb_backend.h +56 -12
- data/vendor/libgit2/include/git2/oid.h +17 -18
- data/vendor/libgit2/include/git2/oidarray.h +40 -0
- data/vendor/libgit2/include/git2/pack.h +86 -7
- data/vendor/libgit2/include/git2/patch.h +274 -0
- data/vendor/libgit2/include/git2/pathspec.h +280 -0
- data/vendor/libgit2/include/git2/proxy.h +96 -0
- data/vendor/libgit2/include/git2/rebase.h +323 -0
- data/vendor/libgit2/include/git2/reflog.h +12 -9
- data/vendor/libgit2/include/git2/refs.h +241 -46
- data/vendor/libgit2/include/git2/refspec.h +20 -4
- data/vendor/libgit2/include/git2/remote.h +636 -209
- data/vendor/libgit2/include/git2/repository.h +267 -57
- data/vendor/libgit2/include/git2/reset.h +36 -6
- data/vendor/libgit2/include/git2/revert.h +91 -0
- data/vendor/libgit2/include/git2/revparse.h +27 -16
- data/vendor/libgit2/include/git2/revwalk.h +78 -35
- data/vendor/libgit2/include/git2/signature.h +32 -5
- data/vendor/libgit2/include/git2/stash.h +160 -21
- data/vendor/libgit2/include/git2/status.h +92 -30
- data/vendor/libgit2/include/git2/submodule.h +226 -133
- data/vendor/libgit2/include/git2/sys/alloc.h +101 -0
- data/vendor/libgit2/include/git2/sys/commit.h +38 -4
- data/vendor/libgit2/include/git2/sys/config.h +68 -9
- data/vendor/libgit2/include/git2/sys/diff.h +94 -0
- data/vendor/libgit2/include/git2/sys/filter.h +332 -0
- data/vendor/libgit2/include/git2/sys/hashsig.h +106 -0
- data/vendor/libgit2/include/git2/sys/index.h +6 -5
- data/vendor/libgit2/include/git2/sys/mempack.h +86 -0
- data/vendor/libgit2/include/git2/sys/merge.h +182 -0
- data/vendor/libgit2/include/git2/sys/odb_backend.h +66 -28
- data/vendor/libgit2/include/git2/sys/openssl.h +38 -0
- data/vendor/libgit2/include/git2/sys/path.h +64 -0
- data/vendor/libgit2/include/git2/sys/refdb_backend.h +79 -19
- data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
- data/vendor/libgit2/include/git2/sys/refs.h +13 -2
- data/vendor/libgit2/include/git2/sys/repository.h +64 -1
- data/vendor/libgit2/include/git2/sys/stream.h +138 -0
- data/vendor/libgit2/include/git2/sys/time.h +31 -0
- data/vendor/libgit2/include/git2/sys/transport.h +439 -0
- data/vendor/libgit2/include/git2/tag.h +11 -2
- data/vendor/libgit2/include/git2/trace.h +1 -1
- data/vendor/libgit2/include/git2/transaction.h +121 -0
- data/vendor/libgit2/include/git2/transport.h +261 -292
- data/vendor/libgit2/include/git2/tree.h +111 -21
- data/vendor/libgit2/include/git2/types.h +244 -32
- data/vendor/libgit2/include/git2/version.h +5 -2
- data/vendor/libgit2/include/git2/worktree.h +255 -0
- data/vendor/libgit2/include/git2.h +50 -40
- data/vendor/libgit2/libgit2.pc.in +13 -0
- data/vendor/libgit2/src/CMakeLists.txt +525 -0
- data/vendor/libgit2/src/alloc.c +55 -0
- data/vendor/libgit2/src/alloc.h +40 -0
- data/vendor/libgit2/src/annotated_commit.c +228 -0
- data/vendor/libgit2/src/annotated_commit.h +52 -0
- data/vendor/libgit2/src/apply.c +855 -0
- data/vendor/libgit2/src/apply.h +25 -0
- data/vendor/libgit2/src/array.h +74 -16
- data/vendor/libgit2/src/attr.c +239 -408
- data/vendor/libgit2/src/attr.h +3 -33
- data/vendor/libgit2/src/attr_file.c +424 -156
- data/vendor/libgit2/src/attr_file.h +95 -23
- data/vendor/libgit2/src/attrcache.c +469 -0
- data/vendor/libgit2/src/attrcache.h +37 -5
- data/vendor/libgit2/src/bitvec.h +75 -0
- data/vendor/libgit2/src/blame.c +532 -0
- data/vendor/libgit2/src/blame.h +95 -0
- data/vendor/libgit2/src/blame_git.c +668 -0
- data/vendor/libgit2/src/blame_git.h +22 -0
- data/vendor/libgit2/src/blob.c +233 -129
- data/vendor/libgit2/src/blob.h +29 -1
- data/vendor/libgit2/src/branch.c +295 -197
- data/vendor/libgit2/src/branch.h +2 -0
- data/vendor/libgit2/src/buf_text.c +52 -27
- data/vendor/libgit2/src/buf_text.h +7 -7
- data/vendor/libgit2/src/buffer.c +609 -52
- data/vendor/libgit2/src/buffer.h +68 -23
- data/vendor/libgit2/src/cache.c +48 -51
- data/vendor/libgit2/src/cache.h +6 -4
- data/vendor/libgit2/src/cc-compat.h +35 -7
- data/vendor/libgit2/src/checkout.c +1827 -483
- data/vendor/libgit2/src/checkout.h +4 -1
- data/vendor/libgit2/src/cherrypick.c +230 -0
- data/vendor/libgit2/src/clone.c +338 -258
- data/vendor/libgit2/src/{compress.h → clone.h} +5 -5
- data/vendor/libgit2/src/commit.c +711 -124
- data/vendor/libgit2/src/commit.h +10 -3
- data/vendor/libgit2/src/commit_list.c +21 -14
- data/vendor/libgit2/src/commit_list.h +9 -3
- data/vendor/libgit2/src/common.h +153 -13
- data/vendor/libgit2/src/config.c +871 -242
- data/vendor/libgit2/src/config.h +58 -14
- data/vendor/libgit2/src/config_backend.h +84 -0
- data/vendor/libgit2/src/config_cache.c +44 -18
- data/vendor/libgit2/src/config_entries.c +259 -0
- data/vendor/libgit2/src/config_entries.h +23 -0
- data/vendor/libgit2/src/config_file.c +837 -1113
- data/vendor/libgit2/src/config_mem.c +224 -0
- data/vendor/libgit2/src/config_parse.c +558 -0
- data/vendor/libgit2/src/config_parse.h +64 -0
- data/vendor/libgit2/src/crlf.c +290 -195
- data/vendor/libgit2/src/date.c +35 -7
- data/vendor/libgit2/src/delta.c +275 -71
- data/vendor/libgit2/src/delta.h +80 -58
- data/vendor/libgit2/src/describe.c +893 -0
- data/vendor/libgit2/src/diff.c +330 -1128
- data/vendor/libgit2/src/diff.h +25 -67
- data/vendor/libgit2/src/diff_driver.c +225 -109
- data/vendor/libgit2/src/diff_driver.h +5 -2
- data/vendor/libgit2/src/diff_file.c +128 -103
- data/vendor/libgit2/src/diff_file.h +17 -12
- data/vendor/libgit2/src/diff_generate.c +1622 -0
- data/vendor/libgit2/src/diff_generate.h +128 -0
- data/vendor/libgit2/src/diff_parse.c +108 -0
- data/vendor/libgit2/src/diff_parse.h +20 -0
- data/vendor/libgit2/src/diff_print.c +578 -218
- data/vendor/libgit2/src/diff_stats.c +362 -0
- data/vendor/libgit2/src/diff_tform.c +429 -257
- data/vendor/libgit2/src/diff_tform.h +25 -0
- data/vendor/libgit2/src/diff_xdiff.c +143 -46
- data/vendor/libgit2/src/diff_xdiff.h +12 -5
- data/vendor/libgit2/src/errors.c +150 -34
- data/vendor/libgit2/src/features.h.in +37 -0
- data/vendor/libgit2/src/fetch.c +69 -46
- data/vendor/libgit2/src/fetch.h +6 -12
- data/vendor/libgit2/src/fetchhead.c +40 -33
- data/vendor/libgit2/src/fetchhead.h +5 -4
- data/vendor/libgit2/src/filebuf.c +163 -61
- data/vendor/libgit2/src/filebuf.h +13 -7
- data/vendor/libgit2/src/fileops.c +549 -407
- data/vendor/libgit2/src/fileops.h +97 -106
- data/vendor/libgit2/src/filter.c +989 -46
- data/vendor/libgit2/src/filter.h +21 -70
- data/vendor/libgit2/src/fnmatch.c +67 -11
- data/vendor/libgit2/src/fnmatch.h +27 -7
- data/vendor/libgit2/src/global.c +257 -63
- data/vendor/libgit2/src/global.h +19 -0
- data/vendor/libgit2/src/graph.c +39 -23
- data/vendor/libgit2/src/hash/hash_collisiondetect.h +51 -0
- data/vendor/libgit2/src/hash/hash_common_crypto.h +61 -0
- data/vendor/libgit2/src/hash/hash_generic.c +3 -3
- data/vendor/libgit2/src/hash/hash_generic.h +10 -5
- data/vendor/libgit2/src/hash/hash_mbedtls.c +38 -0
- data/vendor/libgit2/src/hash/hash_mbedtls.h +24 -0
- data/vendor/libgit2/src/hash/hash_openssl.h +26 -8
- data/vendor/libgit2/src/hash/hash_win32.c +71 -43
- data/vendor/libgit2/src/hash/hash_win32.h +4 -3
- data/vendor/libgit2/src/hash/sha1dc/sha1.c +1900 -0
- data/vendor/libgit2/src/hash/sha1dc/sha1.h +110 -0
- data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +372 -0
- data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +52 -0
- data/vendor/libgit2/src/hash.c +0 -1
- data/vendor/libgit2/src/hash.h +13 -6
- data/vendor/libgit2/src/hashsig.c +121 -126
- data/vendor/libgit2/src/ident.c +129 -0
- data/vendor/libgit2/src/idxmap.c +153 -0
- data/vendor/libgit2/src/idxmap.h +41 -0
- data/vendor/libgit2/src/ignore.c +362 -123
- data/vendor/libgit2/src/ignore.h +16 -4
- data/vendor/libgit2/src/index.c +2131 -692
- data/vendor/libgit2/src/index.h +138 -6
- data/vendor/libgit2/src/indexer.c +866 -266
- data/vendor/libgit2/src/indexer.h +16 -0
- data/vendor/libgit2/src/integer.h +106 -0
- data/vendor/libgit2/src/iterator.c +1888 -967
- data/vendor/libgit2/src/iterator.h +130 -67
- data/vendor/libgit2/src/khash.h +43 -29
- data/vendor/libgit2/src/mailmap.c +485 -0
- data/vendor/libgit2/src/mailmap.h +35 -0
- data/vendor/libgit2/src/map.h +1 -1
- data/vendor/libgit2/src/merge.c +1679 -479
- data/vendor/libgit2/src/merge.h +89 -22
- data/vendor/libgit2/src/merge_driver.c +426 -0
- data/vendor/libgit2/src/merge_driver.h +62 -0
- data/vendor/libgit2/src/merge_file.c +238 -101
- data/vendor/libgit2/src/message.c +4 -28
- data/vendor/libgit2/src/message.h +3 -1
- data/vendor/libgit2/src/mwindow.c +123 -15
- data/vendor/libgit2/src/mwindow.h +10 -1
- data/vendor/libgit2/src/netops.c +178 -499
- data/vendor/libgit2/src/netops.h +51 -27
- data/vendor/libgit2/src/notes.c +251 -94
- data/vendor/libgit2/src/notes.h +5 -2
- data/vendor/libgit2/src/object.c +253 -67
- data/vendor/libgit2/src/object.h +40 -2
- data/vendor/libgit2/src/object_api.c +30 -11
- data/vendor/libgit2/src/odb.c +765 -201
- data/vendor/libgit2/src/odb.h +40 -8
- data/vendor/libgit2/src/odb_loose.c +560 -346
- data/vendor/libgit2/src/odb_mempack.c +185 -0
- data/vendor/libgit2/src/odb_pack.c +117 -73
- data/vendor/libgit2/src/offmap.c +113 -0
- data/vendor/libgit2/src/offmap.h +32 -42
- data/vendor/libgit2/src/oid.c +45 -25
- data/vendor/libgit2/src/oid.h +26 -8
- data/vendor/libgit2/src/oidarray.c +34 -0
- data/vendor/libgit2/src/oidarray.h +20 -0
- data/vendor/libgit2/src/oidmap.c +125 -0
- data/vendor/libgit2/src/oidmap.h +30 -17
- data/vendor/libgit2/src/pack-objects.c +688 -265
- data/vendor/libgit2/src/pack-objects.h +27 -13
- data/vendor/libgit2/src/pack.c +418 -202
- data/vendor/libgit2/src/pack.h +25 -16
- data/vendor/libgit2/src/parse.c +124 -0
- data/vendor/libgit2/src/parse.h +61 -0
- data/vendor/libgit2/src/patch.c +223 -0
- data/vendor/libgit2/src/patch.h +68 -0
- data/vendor/libgit2/src/patch_generate.c +901 -0
- data/vendor/libgit2/src/patch_generate.h +69 -0
- data/vendor/libgit2/src/patch_parse.c +1136 -0
- data/vendor/libgit2/src/patch_parse.h +51 -0
- data/vendor/libgit2/src/path.c +1247 -241
- data/vendor/libgit2/src/path.h +353 -57
- data/vendor/libgit2/src/pathspec.c +586 -58
- data/vendor/libgit2/src/pathspec.h +37 -15
- data/vendor/libgit2/src/pool.c +134 -221
- data/vendor/libgit2/src/pool.h +38 -50
- data/vendor/libgit2/src/posix.c +76 -10
- data/vendor/libgit2/src/posix.h +74 -32
- data/vendor/libgit2/src/pqueue.c +79 -117
- data/vendor/libgit2/src/pqueue.h +38 -82
- data/vendor/libgit2/src/proxy.c +39 -0
- data/vendor/libgit2/src/proxy.h +17 -0
- data/vendor/libgit2/src/push.c +178 -279
- data/vendor/libgit2/src/push.h +93 -4
- data/vendor/libgit2/src/reader.c +265 -0
- data/vendor/libgit2/src/reader.h +107 -0
- data/vendor/libgit2/src/rebase.c +1364 -0
- data/vendor/libgit2/src/refdb.c +74 -19
- data/vendor/libgit2/src/refdb.h +16 -3
- data/vendor/libgit2/src/refdb_fs.c +1472 -603
- data/vendor/libgit2/src/refdb_fs.h +4 -0
- data/vendor/libgit2/src/reflog.c +40 -330
- data/vendor/libgit2/src/reflog.h +8 -2
- data/vendor/libgit2/src/refs.c +641 -225
- data/vendor/libgit2/src/refs.h +53 -6
- data/vendor/libgit2/src/refspec.c +175 -62
- data/vendor/libgit2/src/refspec.h +10 -25
- data/vendor/libgit2/src/remote.c +1741 -723
- data/vendor/libgit2/src/remote.h +17 -5
- data/vendor/libgit2/src/repository.c +1505 -421
- data/vendor/libgit2/src/repository.h +95 -15
- data/vendor/libgit2/src/reset.c +63 -26
- data/vendor/libgit2/src/revert.c +232 -0
- data/vendor/libgit2/src/revparse.c +94 -80
- data/vendor/libgit2/src/revwalk.c +427 -194
- data/vendor/libgit2/src/revwalk.h +14 -5
- data/vendor/libgit2/src/settings.c +290 -0
- data/vendor/libgit2/src/sha1_lookup.c +16 -159
- data/vendor/libgit2/src/sha1_lookup.h +5 -4
- data/vendor/libgit2/src/signature.c +138 -26
- data/vendor/libgit2/src/signature.h +5 -0
- data/vendor/libgit2/src/sortedcache.c +395 -0
- data/vendor/libgit2/src/sortedcache.h +180 -0
- data/vendor/libgit2/src/stash.c +629 -168
- data/vendor/libgit2/src/status.c +125 -75
- data/vendor/libgit2/src/status.h +4 -2
- data/vendor/libgit2/src/stdalloc.c +120 -0
- data/vendor/libgit2/src/stdalloc.h +17 -0
- data/vendor/libgit2/src/stream.h +86 -0
- data/vendor/libgit2/src/streams/mbedtls.c +483 -0
- data/vendor/libgit2/src/streams/mbedtls.h +23 -0
- data/vendor/libgit2/src/streams/openssl.c +789 -0
- data/vendor/libgit2/src/streams/openssl.h +23 -0
- data/vendor/libgit2/src/streams/registry.c +118 -0
- data/vendor/libgit2/src/streams/registry.h +19 -0
- data/vendor/libgit2/src/streams/socket.c +235 -0
- data/vendor/libgit2/src/streams/socket.h +23 -0
- data/vendor/libgit2/src/streams/stransport.c +323 -0
- data/vendor/libgit2/src/streams/stransport.h +21 -0
- data/vendor/libgit2/src/streams/tls.c +73 -0
- data/vendor/libgit2/src/streams/tls.h +31 -0
- data/vendor/libgit2/src/strmap.c +147 -0
- data/vendor/libgit2/src/strmap.h +46 -51
- data/vendor/libgit2/src/strnlen.h +24 -0
- data/vendor/libgit2/src/submodule.c +1633 -877
- data/vendor/libgit2/src/submodule.h +83 -21
- data/vendor/libgit2/src/sysdir.c +355 -0
- data/vendor/libgit2/src/sysdir.h +119 -0
- data/vendor/libgit2/src/tag.c +87 -62
- data/vendor/libgit2/src/tag.h +4 -1
- data/vendor/libgit2/src/thread-utils.c +3 -0
- data/vendor/libgit2/src/thread-utils.h +71 -35
- data/vendor/libgit2/src/trace.c +4 -4
- data/vendor/libgit2/src/trace.h +11 -3
- data/vendor/libgit2/src/trailer.c +416 -0
- data/vendor/libgit2/src/transaction.c +382 -0
- data/vendor/libgit2/src/transaction.h +14 -0
- data/vendor/libgit2/src/transport.c +133 -67
- data/vendor/libgit2/src/transports/auth.c +75 -0
- data/vendor/libgit2/src/transports/auth.h +64 -0
- data/vendor/libgit2/src/transports/auth_negotiate.c +277 -0
- data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
- data/vendor/libgit2/src/transports/cred.c +296 -68
- data/vendor/libgit2/src/transports/cred.h +16 -0
- data/vendor/libgit2/src/transports/cred_helpers.c +4 -0
- data/vendor/libgit2/src/transports/git.c +108 -90
- data/vendor/libgit2/src/transports/http.c +803 -258
- data/vendor/libgit2/src/transports/http.h +25 -0
- data/vendor/libgit2/src/transports/local.c +265 -169
- data/vendor/libgit2/src/transports/smart.c +255 -45
- data/vendor/libgit2/src/transports/smart.h +42 -22
- data/vendor/libgit2/src/transports/smart_pkt.c +250 -159
- data/vendor/libgit2/src/transports/smart_protocol.c +414 -196
- data/vendor/libgit2/src/transports/ssh.c +645 -236
- data/vendor/libgit2/src/transports/ssh.h +14 -0
- data/vendor/libgit2/src/transports/winhttp.c +809 -353
- data/vendor/libgit2/src/tree-cache.c +138 -52
- data/vendor/libgit2/src/tree-cache.h +14 -7
- data/vendor/libgit2/src/tree.c +620 -259
- data/vendor/libgit2/src/tree.h +12 -19
- data/vendor/libgit2/src/tsort.c +3 -2
- data/vendor/libgit2/src/unix/map.c +25 -7
- data/vendor/libgit2/src/unix/posix.h +77 -12
- data/vendor/libgit2/src/unix/pthread.h +56 -0
- data/vendor/libgit2/src/unix/realpath.c +12 -8
- data/vendor/libgit2/src/userdiff.h +208 -0
- data/vendor/libgit2/src/util.c +349 -165
- data/vendor/libgit2/src/util.h +167 -85
- data/vendor/libgit2/src/varint.c +43 -0
- data/vendor/libgit2/src/varint.h +17 -0
- data/vendor/libgit2/src/vector.c +156 -33
- data/vendor/libgit2/src/vector.h +41 -5
- data/vendor/libgit2/src/win32/dir.c +22 -42
- data/vendor/libgit2/src/win32/dir.h +7 -5
- data/vendor/libgit2/src/win32/error.c +6 -32
- data/vendor/libgit2/src/win32/error.h +4 -2
- data/vendor/libgit2/src/win32/findfile.c +62 -69
- data/vendor/libgit2/src/win32/findfile.h +5 -13
- data/vendor/libgit2/src/win32/git2.rc +44 -0
- data/vendor/libgit2/src/win32/map.c +39 -11
- data/vendor/libgit2/src/win32/mingw-compat.h +10 -11
- data/vendor/libgit2/src/win32/msvc-compat.h +10 -33
- data/vendor/libgit2/src/win32/path_w32.c +476 -0
- data/vendor/libgit2/src/win32/path_w32.h +104 -0
- data/vendor/libgit2/src/win32/posix.h +35 -30
- data/vendor/libgit2/src/win32/posix_w32.c +659 -327
- data/vendor/libgit2/src/win32/precompiled.h +7 -2
- data/vendor/libgit2/src/win32/reparse.h +57 -0
- data/vendor/libgit2/src/win32/thread.c +258 -0
- data/vendor/libgit2/src/win32/thread.h +64 -0
- data/vendor/libgit2/src/win32/utf-conv.c +127 -62
- data/vendor/libgit2/src/win32/utf-conv.h +47 -6
- data/vendor/libgit2/src/win32/version.h +21 -4
- data/vendor/libgit2/src/win32/w32_buffer.c +54 -0
- data/vendor/libgit2/src/win32/w32_buffer.h +20 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +438 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +129 -0
- data/vendor/libgit2/src/win32/w32_stack.c +193 -0
- data/vendor/libgit2/src/win32/w32_stack.h +140 -0
- data/vendor/libgit2/src/win32/w32_util.c +95 -0
- data/vendor/libgit2/src/win32/w32_util.h +170 -0
- data/vendor/libgit2/src/win32/win32-compat.h +52 -0
- data/vendor/libgit2/src/worktree.c +578 -0
- data/vendor/libgit2/src/worktree.h +39 -0
- data/vendor/libgit2/src/xdiff/xdiff.h +33 -18
- data/vendor/libgit2/src/xdiff/xdiffi.c +578 -88
- data/vendor/libgit2/src/xdiff/xdiffi.h +3 -2
- data/vendor/libgit2/src/xdiff/xemit.c +106 -45
- data/vendor/libgit2/src/xdiff/xemit.h +3 -3
- data/vendor/libgit2/src/xdiff/xhistogram.c +5 -4
- data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
- data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
- data/vendor/libgit2/src/xdiff/xmerge.c +167 -48
- data/vendor/libgit2/src/xdiff/xpatience.c +42 -10
- data/vendor/libgit2/src/xdiff/xprepare.c +14 -14
- data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
- data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
- data/vendor/libgit2/src/xdiff/xutils.c +60 -56
- data/vendor/libgit2/src/xdiff/xutils.h +3 -5
- data/vendor/libgit2/src/zstream.c +205 -0
- data/vendor/libgit2/src/zstream.h +53 -0
- metadata +281 -233
- data/Rakefile +0 -61
- data/ext/rugged/rugged_diff_patch.c +0 -169
- data/lib/rugged/diff/patch.rb +0 -28
- data/test/blob_test.rb +0 -341
- data/test/branch_test.rb +0 -199
- data/test/commit_test.rb +0 -104
- data/test/config_test.rb +0 -45
- data/test/coverage/cover.rb +0 -133
- data/test/diff_test.rb +0 -777
- data/test/errors_test.rb +0 -34
- data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
- data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
- data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
- data/test/fixtures/archive.tar.gz +0 -0
- data/test/fixtures/attr/attr0 +0 -1
- data/test/fixtures/attr/attr1 +0 -29
- data/test/fixtures/attr/attr2 +0 -21
- data/test/fixtures/attr/attr3 +0 -4
- data/test/fixtures/attr/binfile +0 -1
- data/test/fixtures/attr/dir/file +0 -0
- data/test/fixtures/attr/file +0 -1
- data/test/fixtures/attr/gitattributes +0 -29
- data/test/fixtures/attr/gitignore +0 -2
- data/test/fixtures/attr/ign +0 -1
- data/test/fixtures/attr/macro_bad +0 -1
- data/test/fixtures/attr/macro_test +0 -1
- data/test/fixtures/attr/root_test1 +0 -1
- data/test/fixtures/attr/root_test2 +0 -6
- data/test/fixtures/attr/root_test3 +0 -19
- data/test/fixtures/attr/root_test4.txt +0 -14
- data/test/fixtures/attr/sub/abc +0 -37
- data/test/fixtures/attr/sub/dir/file +0 -0
- data/test/fixtures/attr/sub/file +0 -1
- data/test/fixtures/attr/sub/ign/file +0 -1
- data/test/fixtures/attr/sub/ign/sub/file +0 -1
- data/test/fixtures/attr/sub/sub/dir +0 -0
- data/test/fixtures/attr/sub/sub/file +0 -1
- data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
- data/test/fixtures/attr/sub/subdir_test1 +0 -2
- data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
- data/test/fixtures/diff/another.txt +0 -38
- data/test/fixtures/diff/readme.txt +0 -36
- data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
- data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
- data/test/fixtures/mergedrepo/one.txt +0 -10
- data/test/fixtures/mergedrepo/two.txt +0 -12
- data/test/fixtures/status/current_file +0 -1
- data/test/fixtures/status/ignored_file +0 -1
- data/test/fixtures/status/modified_file +0 -2
- data/test/fixtures/status/new_file +0 -1
- data/test/fixtures/status/staged_changes +0 -2
- data/test/fixtures/status/staged_changes_modified_file +0 -3
- data/test/fixtures/status/staged_delete_modified_file +0 -1
- data/test/fixtures/status/staged_new_file +0 -1
- data/test/fixtures/status/staged_new_file_modified_file +0 -2
- data/test/fixtures/status/subdir/current_file +0 -1
- data/test/fixtures/status/subdir/modified_file +0 -2
- data/test/fixtures/status/subdir/new_file +0 -1
- data/test/fixtures/status/subdir.txt +0 -2
- data/test/fixtures/status//350/277/231 +0 -1
- data/test/fixtures/testrepo.git/HEAD +0 -1
- data/test/fixtures/testrepo.git/config +0 -13
- data/test/fixtures/testrepo.git/description +0 -1
- data/test/fixtures/testrepo.git/index +0 -0
- data/test/fixtures/testrepo.git/info/exclude +0 -6
- data/test/fixtures/testrepo.git/logs/HEAD +0 -3
- data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
- data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
- data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
- data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
- data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
- data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
- data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
- data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
- data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
- data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
- data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
- data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
- data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
- data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
- data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
- data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
- data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
- data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
- data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
- data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
- data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
- data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
- data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
- data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
- data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
- data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
- data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
- data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
- data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
- data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
- data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
- data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
- data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
- data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
- data/test/fixtures/testrepo.git/packed-refs +0 -2
- data/test/fixtures/testrepo.git/refs/heads/master +0 -1
- data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
- data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
- data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
- data/test/fixtures/text_file.md +0 -464
- data/test/fixtures/unsymlinked.git/HEAD +0 -1
- data/test/fixtures/unsymlinked.git/config +0 -6
- data/test/fixtures/unsymlinked.git/description +0 -1
- data/test/fixtures/unsymlinked.git/info/exclude +0 -2
- data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
- data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
- data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
- data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
- data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
- data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
- data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
- data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
- data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
- data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
- data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
- data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
- data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
- data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
- data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
- data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
- data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
- data/test/index_test.rb +0 -333
- data/test/lib_test.rb +0 -127
- data/test/note_test.rb +0 -158
- data/test/object_test.rb +0 -43
- data/test/reference_test.rb +0 -207
- data/test/remote_test.rb +0 -324
- data/test/repo_pack_test.rb +0 -24
- data/test/repo_reset_test.rb +0 -82
- data/test/repo_test.rb +0 -402
- data/test/tag_test.rb +0 -68
- data/test/test_helper.rb +0 -92
- data/test/tree_test.rb +0 -91
- data/test/walker_test.rb +0 -88
- data/vendor/libgit2/Makefile.embed +0 -42
- data/vendor/libgit2/include/git2/push.h +0 -131
- data/vendor/libgit2/include/git2/threads.h +0 -50
- data/vendor/libgit2/src/amiga/map.c +0 -48
- data/vendor/libgit2/src/bswap.h +0 -97
- data/vendor/libgit2/src/compress.c +0 -53
- data/vendor/libgit2/src/config_file.h +0 -60
- data/vendor/libgit2/src/delta-apply.c +0 -134
- data/vendor/libgit2/src/delta-apply.h +0 -50
- data/vendor/libgit2/src/diff_patch.c +0 -995
- data/vendor/libgit2/src/diff_patch.h +0 -46
- data/vendor/libgit2/src/hashsig.h +0 -72
- data/vendor/libgit2/src/merge_file.h +0 -71
- data/vendor/libgit2/src/win32/pthread.c +0 -144
- data/vendor/libgit2/src/win32/pthread.h +0 -50
data/vendor/libgit2/src/index.c
CHANGED
@@ -5,17 +5,21 @@
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
6
6
|
*/
|
7
7
|
|
8
|
+
#include "index.h"
|
9
|
+
|
8
10
|
#include <stddef.h>
|
9
11
|
|
10
|
-
#include "common.h"
|
11
12
|
#include "repository.h"
|
12
|
-
#include "index.h"
|
13
13
|
#include "tree.h"
|
14
14
|
#include "tree-cache.h"
|
15
15
|
#include "hash.h"
|
16
16
|
#include "iterator.h"
|
17
17
|
#include "pathspec.h"
|
18
18
|
#include "ignore.h"
|
19
|
+
#include "blob.h"
|
20
|
+
#include "idxmap.h"
|
21
|
+
#include "diff.h"
|
22
|
+
#include "varint.h"
|
19
23
|
|
20
24
|
#include "git2/odb.h"
|
21
25
|
#include "git2/oid.h"
|
@@ -23,17 +27,43 @@
|
|
23
27
|
#include "git2/config.h"
|
24
28
|
#include "git2/sys/index.h"
|
25
29
|
|
26
|
-
#define
|
27
|
-
|
28
|
-
|
30
|
+
#define INSERT_IN_MAP_EX(idx, map, e, err) do { \
|
31
|
+
if ((idx)->ignore_case) \
|
32
|
+
git_idxmap_icase_insert((git_idxmap_icase *) (map), (e), (e), (err)); \
|
33
|
+
else \
|
34
|
+
git_idxmap_insert((map), (e), (e), (err)); \
|
35
|
+
} while (0)
|
36
|
+
|
37
|
+
#define INSERT_IN_MAP(idx, e, err) INSERT_IN_MAP_EX(idx, (idx)->entries_map, e, err)
|
38
|
+
|
39
|
+
#define LOOKUP_IN_MAP(p, idx, k) do { \
|
40
|
+
if ((idx)->ignore_case) \
|
41
|
+
(p) = git_idxmap_icase_lookup_index((git_idxmap_icase *) index->entries_map, (k)); \
|
42
|
+
else \
|
43
|
+
(p) = git_idxmap_lookup_index(index->entries_map, (k)); \
|
44
|
+
} while (0)
|
45
|
+
|
46
|
+
#define DELETE_IN_MAP(idx, e) do { \
|
47
|
+
if ((idx)->ignore_case) \
|
48
|
+
git_idxmap_icase_delete((git_idxmap_icase *) (idx)->entries_map, (e)); \
|
49
|
+
else \
|
50
|
+
git_idxmap_delete((idx)->entries_map, (e)); \
|
51
|
+
} while (0)
|
52
|
+
|
53
|
+
static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
|
54
|
+
unsigned int flags,
|
55
|
+
git_index_matched_path_cb cb, void *payload);
|
29
56
|
|
30
57
|
#define minimal_entry_size (offsetof(struct entry_short, path))
|
31
58
|
|
32
59
|
static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
|
33
60
|
static const size_t INDEX_HEADER_SIZE = 12;
|
34
61
|
|
35
|
-
static const unsigned int
|
62
|
+
static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2;
|
63
|
+
static const unsigned int INDEX_VERSION_NUMBER_LB = 2;
|
36
64
|
static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;
|
65
|
+
static const unsigned int INDEX_VERSION_NUMBER_COMP = 4;
|
66
|
+
static const unsigned int INDEX_VERSION_NUMBER_UB = 4;
|
37
67
|
|
38
68
|
static const unsigned int INDEX_HEADER_SIG = 0x44495243;
|
39
69
|
static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
|
@@ -89,76 +119,101 @@ struct entry_long {
|
|
89
119
|
|
90
120
|
struct entry_srch_key {
|
91
121
|
const char *path;
|
122
|
+
size_t pathlen;
|
92
123
|
int stage;
|
93
124
|
};
|
94
125
|
|
126
|
+
struct entry_internal {
|
127
|
+
git_index_entry entry;
|
128
|
+
size_t pathlen;
|
129
|
+
char path[GIT_FLEX_ARRAY];
|
130
|
+
};
|
131
|
+
|
132
|
+
struct reuc_entry_internal {
|
133
|
+
git_index_reuc_entry entry;
|
134
|
+
size_t pathlen;
|
135
|
+
char path[GIT_FLEX_ARRAY];
|
136
|
+
};
|
137
|
+
|
138
|
+
bool git_index__enforce_unsaved_safety = false;
|
139
|
+
|
95
140
|
/* local declarations */
|
96
|
-
static
|
97
|
-
static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size);
|
141
|
+
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size);
|
98
142
|
static int read_header(struct index_header *dest, const void *buffer);
|
99
143
|
|
100
144
|
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
|
101
145
|
static bool is_index_extended(git_index *index);
|
102
|
-
static int write_index(git_index *index, git_filebuf *file);
|
103
|
-
|
104
|
-
static int index_find(size_t *at_pos, git_index *index, const char *path, int stage);
|
146
|
+
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
|
105
147
|
|
106
148
|
static void index_entry_free(git_index_entry *entry);
|
107
149
|
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
|
108
150
|
|
109
|
-
|
151
|
+
int git_index_entry_srch(const void *key, const void *array_member)
|
110
152
|
{
|
111
153
|
const struct entry_srch_key *srch_key = key;
|
112
|
-
const
|
113
|
-
int
|
114
|
-
|
115
|
-
|
154
|
+
const struct entry_internal *entry = array_member;
|
155
|
+
int cmp;
|
156
|
+
size_t len1, len2, len;
|
157
|
+
|
158
|
+
len1 = srch_key->pathlen;
|
159
|
+
len2 = entry->pathlen;
|
160
|
+
len = len1 < len2 ? len1 : len2;
|
161
|
+
|
162
|
+
cmp = memcmp(srch_key->path, entry->path, len);
|
163
|
+
if (cmp)
|
164
|
+
return cmp;
|
165
|
+
if (len1 < len2)
|
166
|
+
return -1;
|
167
|
+
if (len1 > len2)
|
168
|
+
return 1;
|
116
169
|
|
117
|
-
if (
|
118
|
-
|
170
|
+
if (srch_key->stage != GIT_INDEX_STAGE_ANY)
|
171
|
+
return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
|
119
172
|
|
120
|
-
return
|
173
|
+
return 0;
|
121
174
|
}
|
122
175
|
|
123
|
-
|
176
|
+
int git_index_entry_isrch(const void *key, const void *array_member)
|
124
177
|
{
|
125
178
|
const struct entry_srch_key *srch_key = key;
|
126
|
-
const
|
127
|
-
int
|
179
|
+
const struct entry_internal *entry = array_member;
|
180
|
+
int cmp;
|
181
|
+
size_t len1, len2, len;
|
128
182
|
|
129
|
-
|
183
|
+
len1 = srch_key->pathlen;
|
184
|
+
len2 = entry->pathlen;
|
185
|
+
len = len1 < len2 ? len1 : len2;
|
130
186
|
|
131
|
-
|
132
|
-
ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
|
187
|
+
cmp = strncasecmp(srch_key->path, entry->path, len);
|
133
188
|
|
134
|
-
|
135
|
-
|
189
|
+
if (cmp)
|
190
|
+
return cmp;
|
191
|
+
if (len1 < len2)
|
192
|
+
return -1;
|
193
|
+
if (len1 > len2)
|
194
|
+
return 1;
|
136
195
|
|
137
|
-
|
138
|
-
|
139
|
-
return strcmp((const char *)a, (const char *)b);
|
140
|
-
}
|
196
|
+
if (srch_key->stage != GIT_INDEX_STAGE_ANY)
|
197
|
+
return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
|
141
198
|
|
142
|
-
|
143
|
-
{
|
144
|
-
return strcasecmp((const char *)a, (const char *)b);
|
199
|
+
return 0;
|
145
200
|
}
|
146
201
|
|
147
|
-
static int
|
202
|
+
static int index_entry_srch_path(const void *path, const void *array_member)
|
148
203
|
{
|
149
204
|
const git_index_entry *entry = array_member;
|
150
205
|
|
151
206
|
return strcmp((const char *)path, entry->path);
|
152
207
|
}
|
153
208
|
|
154
|
-
static int
|
209
|
+
static int index_entry_isrch_path(const void *path, const void *array_member)
|
155
210
|
{
|
156
211
|
const git_index_entry *entry = array_member;
|
157
212
|
|
158
213
|
return strcasecmp((const char *)path, entry->path);
|
159
214
|
}
|
160
215
|
|
161
|
-
|
216
|
+
int git_index_entry_cmp(const void *a, const void *b)
|
162
217
|
{
|
163
218
|
int diff;
|
164
219
|
const git_index_entry *entry_a = a;
|
@@ -167,12 +222,12 @@ static int index_cmp(const void *a, const void *b)
|
|
167
222
|
diff = strcmp(entry_a->path, entry_b->path);
|
168
223
|
|
169
224
|
if (diff == 0)
|
170
|
-
diff = (
|
225
|
+
diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
|
171
226
|
|
172
227
|
return diff;
|
173
228
|
}
|
174
229
|
|
175
|
-
|
230
|
+
int git_index_entry_icmp(const void *a, const void *b)
|
176
231
|
{
|
177
232
|
int diff;
|
178
233
|
const git_index_entry *entry_a = a;
|
@@ -181,7 +236,7 @@ static int index_icmp(const void *a, const void *b)
|
|
181
236
|
diff = strcasecmp(entry_a->path, entry_b->path);
|
182
237
|
|
183
238
|
if (diff == 0)
|
184
|
-
diff = (
|
239
|
+
diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
|
185
240
|
|
186
241
|
return diff;
|
187
242
|
}
|
@@ -261,7 +316,21 @@ static int reuc_icmp(const void *a, const void *b)
|
|
261
316
|
return strcasecmp(info_a->path, info_b->path);
|
262
317
|
}
|
263
318
|
|
264
|
-
static
|
319
|
+
static void index_entry_reuc_free(git_index_reuc_entry *reuc)
|
320
|
+
{
|
321
|
+
git__free(reuc);
|
322
|
+
}
|
323
|
+
|
324
|
+
static void index_entry_free(git_index_entry *entry)
|
325
|
+
{
|
326
|
+
if (!entry)
|
327
|
+
return;
|
328
|
+
|
329
|
+
memset(&entry->id, 0, sizeof(entry->id));
|
330
|
+
git__free(entry);
|
331
|
+
}
|
332
|
+
|
333
|
+
unsigned int git_index__create_mode(unsigned int mode)
|
265
334
|
{
|
266
335
|
if (S_ISLNK(mode))
|
267
336
|
return S_IFLNK;
|
@@ -269,7 +338,7 @@ static unsigned int index_create_mode(unsigned int mode)
|
|
269
338
|
if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
|
270
339
|
return (S_IFLNK | S_IFDIR);
|
271
340
|
|
272
|
-
return S_IFREG | (
|
341
|
+
return S_IFREG | GIT_PERMS_CANONICAL(mode);
|
273
342
|
}
|
274
343
|
|
275
344
|
static unsigned int index_merge_mode(
|
@@ -281,24 +350,52 @@ static unsigned int index_merge_mode(
|
|
281
350
|
|
282
351
|
if (index->distrust_filemode && S_ISREG(mode))
|
283
352
|
return (existing && S_ISREG(existing->mode)) ?
|
284
|
-
existing->mode :
|
353
|
+
existing->mode : git_index__create_mode(0666);
|
354
|
+
|
355
|
+
return git_index__create_mode(mode);
|
356
|
+
}
|
357
|
+
|
358
|
+
GIT_INLINE(int) index_find_in_entries(
|
359
|
+
size_t *out, git_vector *entries, git_vector_cmp entry_srch,
|
360
|
+
const char *path, size_t path_len, int stage)
|
361
|
+
{
|
362
|
+
struct entry_srch_key srch_key;
|
363
|
+
srch_key.path = path;
|
364
|
+
srch_key.pathlen = !path_len ? strlen(path) : path_len;
|
365
|
+
srch_key.stage = stage;
|
366
|
+
return git_vector_bsearch2(out, entries, entry_srch, &srch_key);
|
367
|
+
}
|
285
368
|
|
286
|
-
|
369
|
+
GIT_INLINE(int) index_find(
|
370
|
+
size_t *out, git_index *index,
|
371
|
+
const char *path, size_t path_len, int stage)
|
372
|
+
{
|
373
|
+
git_vector_sort(&index->entries);
|
374
|
+
|
375
|
+
return index_find_in_entries(
|
376
|
+
out, &index->entries, index->entries_search, path, path_len, stage);
|
287
377
|
}
|
288
378
|
|
289
379
|
void git_index__set_ignore_case(git_index *index, bool ignore_case)
|
290
380
|
{
|
291
381
|
index->ignore_case = ignore_case;
|
292
382
|
|
293
|
-
|
294
|
-
|
295
|
-
|
383
|
+
if (ignore_case) {
|
384
|
+
index->entries_cmp_path = git__strcasecmp_cb;
|
385
|
+
index->entries_search = git_index_entry_isrch;
|
386
|
+
index->entries_search_path = index_entry_isrch_path;
|
387
|
+
index->reuc_search = reuc_isrch;
|
388
|
+
} else {
|
389
|
+
index->entries_cmp_path = git__strcmp_cb;
|
390
|
+
index->entries_search = git_index_entry_srch;
|
391
|
+
index->entries_search_path = index_entry_srch_path;
|
392
|
+
index->reuc_search = reuc_srch;
|
393
|
+
}
|
296
394
|
|
297
|
-
git_vector_set_cmp(&index->entries,
|
395
|
+
git_vector_set_cmp(&index->entries,
|
396
|
+
ignore_case ? git_index_entry_icmp : git_index_entry_cmp);
|
298
397
|
git_vector_sort(&index->entries);
|
299
398
|
|
300
|
-
index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
|
301
|
-
|
302
399
|
git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
|
303
400
|
git_vector_sort(&index->reuc);
|
304
401
|
}
|
@@ -306,35 +403,50 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
|
|
306
403
|
int git_index_open(git_index **index_out, const char *index_path)
|
307
404
|
{
|
308
405
|
git_index *index;
|
406
|
+
int error = -1;
|
309
407
|
|
310
408
|
assert(index_out);
|
311
409
|
|
312
410
|
index = git__calloc(1, sizeof(git_index));
|
313
|
-
|
411
|
+
GIT_ERROR_CHECK_ALLOC(index);
|
412
|
+
|
413
|
+
git_pool_init(&index->tree_pool, 1);
|
314
414
|
|
315
415
|
if (index_path != NULL) {
|
316
416
|
index->index_file_path = git__strdup(index_path);
|
317
|
-
|
417
|
+
if (!index->index_file_path)
|
418
|
+
goto fail;
|
318
419
|
|
319
420
|
/* Check if index file is stored on disk already */
|
320
421
|
if (git_path_exists(index->index_file_path) == true)
|
321
422
|
index->on_disk = 1;
|
322
423
|
}
|
323
424
|
|
324
|
-
if (git_vector_init(&index->entries, 32,
|
325
|
-
|
326
|
-
git_vector_init(&index->
|
327
|
-
|
425
|
+
if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
|
426
|
+
git_idxmap_alloc(&index->entries_map) < 0 ||
|
427
|
+
git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
|
428
|
+
git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
|
429
|
+
git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
|
430
|
+
goto fail;
|
328
431
|
|
329
|
-
index->entries_cmp_path =
|
330
|
-
index->entries_search =
|
331
|
-
index->entries_search_path =
|
432
|
+
index->entries_cmp_path = git__strcmp_cb;
|
433
|
+
index->entries_search = git_index_entry_srch;
|
434
|
+
index->entries_search_path = index_entry_srch_path;
|
332
435
|
index->reuc_search = reuc_srch;
|
436
|
+
index->version = INDEX_VERSION_NUMBER_DEFAULT;
|
437
|
+
|
438
|
+
if (index_path != NULL && (error = git_index_read(index, true)) < 0)
|
439
|
+
goto fail;
|
333
440
|
|
334
441
|
*index_out = index;
|
335
442
|
GIT_REFCOUNT_INC(index);
|
336
443
|
|
337
|
-
return
|
444
|
+
return 0;
|
445
|
+
|
446
|
+
fail:
|
447
|
+
git_pool_clear(&index->tree_pool);
|
448
|
+
git_index_free(index);
|
449
|
+
return error;
|
338
450
|
}
|
339
451
|
|
340
452
|
int git_index_new(git_index **out)
|
@@ -344,10 +456,17 @@ int git_index_new(git_index **out)
|
|
344
456
|
|
345
457
|
static void index_free(git_index *index)
|
346
458
|
{
|
459
|
+
/* index iterators increment the refcount of the index, so if we
|
460
|
+
* get here then there should be no outstanding iterators.
|
461
|
+
*/
|
462
|
+
assert(!git_atomic_get(&index->readers));
|
463
|
+
|
347
464
|
git_index_clear(index);
|
465
|
+
git_idxmap_free(index->entries_map);
|
348
466
|
git_vector_free(&index->entries);
|
349
467
|
git_vector_free(&index->names);
|
350
468
|
git_vector_free(&index->reuc);
|
469
|
+
git_vector_free(&index->deleted);
|
351
470
|
|
352
471
|
git__free(index->index_file_path);
|
353
472
|
|
@@ -363,54 +482,93 @@ void git_index_free(git_index *index)
|
|
363
482
|
GIT_REFCOUNT_DEC(index, index_free);
|
364
483
|
}
|
365
484
|
|
366
|
-
|
485
|
+
/* call with locked index */
|
486
|
+
static void index_free_deleted(git_index *index)
|
367
487
|
{
|
488
|
+
int readers = (int)git_atomic_get(&index->readers);
|
368
489
|
size_t i;
|
369
490
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
491
|
+
if (readers > 0 || !index->deleted.length)
|
492
|
+
return;
|
493
|
+
|
494
|
+
for (i = 0; i < index->deleted.length; ++i) {
|
495
|
+
git_index_entry *ie = git__swap(index->deleted.contents[i], NULL);
|
496
|
+
index_entry_free(ie);
|
374
497
|
}
|
375
498
|
|
376
|
-
git_vector_clear(
|
499
|
+
git_vector_clear(&index->deleted);
|
377
500
|
}
|
378
501
|
|
379
|
-
|
502
|
+
/* call with locked index */
|
503
|
+
static int index_remove_entry(git_index *index, size_t pos)
|
380
504
|
{
|
505
|
+
int error = 0;
|
506
|
+
git_index_entry *entry = git_vector_get(&index->entries, pos);
|
507
|
+
|
508
|
+
if (entry != NULL) {
|
509
|
+
git_tree_cache_invalidate_path(index->tree, entry->path);
|
510
|
+
DELETE_IN_MAP(index, entry);
|
511
|
+
}
|
512
|
+
|
513
|
+
error = git_vector_remove(&index->entries, pos);
|
514
|
+
|
515
|
+
if (!error) {
|
516
|
+
if (git_atomic_get(&index->readers) > 0) {
|
517
|
+
error = git_vector_insert(&index->deleted, entry);
|
518
|
+
} else {
|
519
|
+
index_entry_free(entry);
|
520
|
+
}
|
521
|
+
|
522
|
+
index->dirty = 1;
|
523
|
+
}
|
524
|
+
|
525
|
+
return error;
|
526
|
+
}
|
527
|
+
|
528
|
+
int git_index_clear(git_index *index)
|
529
|
+
{
|
530
|
+
int error = 0;
|
531
|
+
|
381
532
|
assert(index);
|
382
533
|
|
383
|
-
|
534
|
+
index->dirty = 1;
|
535
|
+
index->tree = NULL;
|
536
|
+
git_pool_clear(&index->tree_pool);
|
537
|
+
|
538
|
+
git_idxmap_clear(index->entries_map);
|
539
|
+
while (!error && index->entries.length > 0)
|
540
|
+
error = index_remove_entry(index, index->entries.length - 1);
|
541
|
+
index_free_deleted(index);
|
542
|
+
|
384
543
|
git_index_reuc_clear(index);
|
385
544
|
git_index_name_clear(index);
|
386
545
|
|
387
546
|
git_futils_filestamp_set(&index->stamp, NULL);
|
388
547
|
|
389
|
-
|
390
|
-
index->tree = NULL;
|
548
|
+
return error;
|
391
549
|
}
|
392
550
|
|
393
551
|
static int create_index_error(int error, const char *msg)
|
394
552
|
{
|
395
|
-
|
553
|
+
git_error_set_str(GIT_ERROR_INDEX, msg);
|
396
554
|
return error;
|
397
555
|
}
|
398
556
|
|
399
|
-
int git_index_set_caps(git_index *index,
|
557
|
+
int git_index_set_caps(git_index *index, int caps)
|
400
558
|
{
|
401
|
-
int old_ignore_case;
|
559
|
+
unsigned int old_ignore_case;
|
402
560
|
|
403
561
|
assert(index);
|
404
562
|
|
405
563
|
old_ignore_case = index->ignore_case;
|
406
564
|
|
407
|
-
if (caps ==
|
565
|
+
if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) {
|
408
566
|
git_repository *repo = INDEX_OWNER(index);
|
409
567
|
int val;
|
410
568
|
|
411
569
|
if (!repo)
|
412
570
|
return create_index_error(
|
413
|
-
-1, "
|
571
|
+
-1, "cannot access repository to set index caps");
|
414
572
|
|
415
573
|
if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
|
416
574
|
index->ignore_case = (val != 0);
|
@@ -420,91 +578,240 @@ int git_index_set_caps(git_index *index, unsigned int caps)
|
|
420
578
|
index->no_symlinks = (val == 0);
|
421
579
|
}
|
422
580
|
else {
|
423
|
-
index->ignore_case = ((caps &
|
424
|
-
index->distrust_filemode = ((caps &
|
425
|
-
index->no_symlinks = ((caps &
|
581
|
+
index->ignore_case = ((caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0);
|
582
|
+
index->distrust_filemode = ((caps & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0);
|
583
|
+
index->no_symlinks = ((caps & GIT_INDEX_CAPABILITY_NO_SYMLINKS) != 0);
|
426
584
|
}
|
427
585
|
|
428
586
|
if (old_ignore_case != index->ignore_case) {
|
429
|
-
git_index__set_ignore_case(index, index->ignore_case);
|
587
|
+
git_index__set_ignore_case(index, (bool)index->ignore_case);
|
430
588
|
}
|
431
589
|
|
432
590
|
return 0;
|
433
591
|
}
|
434
592
|
|
435
|
-
|
593
|
+
int git_index_caps(const git_index *index)
|
594
|
+
{
|
595
|
+
return ((index->ignore_case ? GIT_INDEX_CAPABILITY_IGNORE_CASE : 0) |
|
596
|
+
(index->distrust_filemode ? GIT_INDEX_CAPABILITY_NO_FILEMODE : 0) |
|
597
|
+
(index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0));
|
598
|
+
}
|
599
|
+
|
600
|
+
const git_oid *git_index_checksum(git_index *index)
|
601
|
+
{
|
602
|
+
return &index->checksum;
|
603
|
+
}
|
604
|
+
|
605
|
+
/**
|
606
|
+
* Returns 1 for changed, 0 for not changed and <0 for errors
|
607
|
+
*/
|
608
|
+
static int compare_checksum(git_index *index)
|
436
609
|
{
|
437
|
-
|
438
|
-
|
439
|
-
|
610
|
+
int fd;
|
611
|
+
ssize_t bytes_read;
|
612
|
+
git_oid checksum = {{ 0 }};
|
613
|
+
|
614
|
+
if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0)
|
615
|
+
return fd;
|
616
|
+
|
617
|
+
if (p_lseek(fd, -20, SEEK_END) < 0) {
|
618
|
+
p_close(fd);
|
619
|
+
git_error_set(GIT_ERROR_OS, "failed to seek to end of file");
|
620
|
+
return -1;
|
621
|
+
}
|
622
|
+
|
623
|
+
bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
|
624
|
+
p_close(fd);
|
625
|
+
|
626
|
+
if (bytes_read < 0)
|
627
|
+
return -1;
|
628
|
+
|
629
|
+
return !!git_oid_cmp(&checksum, &index->checksum);
|
440
630
|
}
|
441
631
|
|
442
|
-
int git_index_read(git_index *index)
|
632
|
+
int git_index_read(git_index *index, int force)
|
443
633
|
{
|
444
634
|
int error = 0, updated;
|
445
635
|
git_buf buffer = GIT_BUF_INIT;
|
446
|
-
git_futils_filestamp stamp =
|
636
|
+
git_futils_filestamp stamp = index->stamp;
|
447
637
|
|
448
638
|
if (!index->index_file_path)
|
449
639
|
return create_index_error(-1,
|
450
|
-
"
|
640
|
+
"failed to read index: The index is in-memory only");
|
641
|
+
|
642
|
+
index->on_disk = git_path_exists(index->index_file_path);
|
643
|
+
|
644
|
+
if (!index->on_disk) {
|
645
|
+
if (force && (error = git_index_clear(index)) < 0)
|
646
|
+
return error;
|
451
647
|
|
452
|
-
|
453
|
-
git_index_clear(index);
|
454
|
-
index->on_disk = 0;
|
648
|
+
index->dirty = 0;
|
455
649
|
return 0;
|
456
650
|
}
|
457
651
|
|
458
|
-
updated = git_futils_filestamp_check(&stamp, index->index_file_path)
|
459
|
-
|
652
|
+
if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
|
653
|
+
((updated = compare_checksum(index)) < 0)) {
|
654
|
+
git_error_set(
|
655
|
+
GIT_ERROR_INDEX,
|
656
|
+
"failed to read index: '%s' no longer exists",
|
657
|
+
index->index_file_path);
|
460
658
|
return updated;
|
659
|
+
}
|
660
|
+
|
661
|
+
if (!updated && !force)
|
662
|
+
return 0;
|
461
663
|
|
462
664
|
error = git_futils_readbuffer(&buffer, index->index_file_path);
|
463
665
|
if (error < 0)
|
464
666
|
return error;
|
465
667
|
|
466
|
-
|
467
|
-
|
668
|
+
index->tree = NULL;
|
669
|
+
git_pool_clear(&index->tree_pool);
|
670
|
+
|
671
|
+
error = git_index_clear(index);
|
468
672
|
|
469
673
|
if (!error)
|
674
|
+
error = parse_index(index, buffer.ptr, buffer.size);
|
675
|
+
|
676
|
+
if (!error) {
|
470
677
|
git_futils_filestamp_set(&index->stamp, &stamp);
|
678
|
+
index->dirty = 0;
|
679
|
+
}
|
471
680
|
|
472
|
-
|
681
|
+
git_buf_dispose(&buffer);
|
473
682
|
return error;
|
474
683
|
}
|
475
684
|
|
476
|
-
int
|
685
|
+
int git_index_read_safely(git_index *index)
|
686
|
+
{
|
687
|
+
if (git_index__enforce_unsaved_safety && index->dirty) {
|
688
|
+
git_error_set(GIT_ERROR_INDEX,
|
689
|
+
"the index has unsaved changes that would be overwritten by this operation");
|
690
|
+
return GIT_EINDEXDIRTY;
|
691
|
+
}
|
692
|
+
|
693
|
+
return git_index_read(index, false);
|
694
|
+
}
|
695
|
+
|
696
|
+
int git_index__changed_relative_to(
|
697
|
+
git_index *index, const git_oid *checksum)
|
698
|
+
{
|
699
|
+
/* attempt to update index (ignoring errors) */
|
700
|
+
if (git_index_read(index, false) < 0)
|
701
|
+
git_error_clear();
|
702
|
+
|
703
|
+
return !!git_oid_cmp(&index->checksum, checksum);
|
704
|
+
}
|
705
|
+
|
706
|
+
static bool is_racy_entry(git_index *index, const git_index_entry *entry)
|
707
|
+
{
|
708
|
+
/* Git special-cases submodules in the check */
|
709
|
+
if (S_ISGITLINK(entry->mode))
|
710
|
+
return false;
|
711
|
+
|
712
|
+
return git_index_entry_newer_than_index(entry, index);
|
713
|
+
}
|
714
|
+
|
715
|
+
/*
|
716
|
+
* Force the next diff to take a look at those entries which have the
|
717
|
+
* same timestamp as the current index.
|
718
|
+
*/
|
719
|
+
static int truncate_racily_clean(git_index *index)
|
477
720
|
{
|
478
|
-
|
721
|
+
size_t i;
|
479
722
|
int error;
|
723
|
+
git_index_entry *entry;
|
724
|
+
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
|
725
|
+
git_diff *diff = NULL;
|
726
|
+
git_vector paths = GIT_VECTOR_INIT;
|
727
|
+
git_diff_delta *delta;
|
480
728
|
|
481
|
-
if
|
482
|
-
|
483
|
-
|
729
|
+
/* Nothing to do if there's no repo to talk about */
|
730
|
+
if (!INDEX_OWNER(index))
|
731
|
+
return 0;
|
484
732
|
|
485
|
-
|
486
|
-
|
733
|
+
/* If there's no workdir, we can't know where to even check */
|
734
|
+
if (!git_repository_workdir(INDEX_OWNER(index)))
|
735
|
+
return 0;
|
487
736
|
|
488
|
-
|
489
|
-
|
490
|
-
|
737
|
+
diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
738
|
+
git_vector_foreach(&index->entries, i, entry) {
|
739
|
+
if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 &&
|
740
|
+
is_racy_entry(index, entry))
|
741
|
+
git_vector_insert(&paths, (char *)entry->path);
|
742
|
+
}
|
743
|
+
|
744
|
+
if (paths.length == 0)
|
745
|
+
goto done;
|
491
746
|
|
492
|
-
|
493
|
-
|
747
|
+
diff_opts.pathspec.count = paths.length;
|
748
|
+
diff_opts.pathspec.strings = (char **)paths.contents;
|
749
|
+
|
750
|
+
if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
|
494
751
|
return error;
|
752
|
+
|
753
|
+
git_vector_foreach(&diff->deltas, i, delta) {
|
754
|
+
entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0);
|
755
|
+
|
756
|
+
/* Ensure that we have a stage 0 for this file (ie, it's not a
|
757
|
+
* conflict), otherwise smudging it is quite pointless.
|
758
|
+
*/
|
759
|
+
if (entry) {
|
760
|
+
entry->file_size = 0;
|
761
|
+
index->dirty = 1;
|
762
|
+
}
|
495
763
|
}
|
496
764
|
|
497
|
-
|
498
|
-
|
765
|
+
done:
|
766
|
+
git_diff_free(diff);
|
767
|
+
git_vector_free(&paths);
|
768
|
+
return 0;
|
769
|
+
}
|
499
770
|
|
500
|
-
|
501
|
-
|
502
|
-
|
771
|
+
unsigned git_index_version(git_index *index)
|
772
|
+
{
|
773
|
+
assert(index);
|
774
|
+
|
775
|
+
return index->version;
|
776
|
+
}
|
777
|
+
|
778
|
+
int git_index_set_version(git_index *index, unsigned int version)
|
779
|
+
{
|
780
|
+
assert(index);
|
781
|
+
|
782
|
+
if (version < INDEX_VERSION_NUMBER_LB ||
|
783
|
+
version > INDEX_VERSION_NUMBER_UB) {
|
784
|
+
git_error_set(GIT_ERROR_INDEX, "invalid version number");
|
785
|
+
return -1;
|
786
|
+
}
|
787
|
+
|
788
|
+
index->version = version;
|
503
789
|
|
504
|
-
index->on_disk = 1;
|
505
790
|
return 0;
|
506
791
|
}
|
507
792
|
|
793
|
+
int git_index_write(git_index *index)
|
794
|
+
{
|
795
|
+
git_indexwriter writer = GIT_INDEXWRITER_INIT;
|
796
|
+
int error;
|
797
|
+
|
798
|
+
truncate_racily_clean(index);
|
799
|
+
|
800
|
+
if ((error = git_indexwriter_init(&writer, index)) == 0 &&
|
801
|
+
(error = git_indexwriter_commit(&writer)) == 0)
|
802
|
+
index->dirty = 0;
|
803
|
+
|
804
|
+
git_indexwriter_cleanup(&writer);
|
805
|
+
|
806
|
+
return error;
|
807
|
+
}
|
808
|
+
|
809
|
+
const char * git_index_path(const git_index *index)
|
810
|
+
{
|
811
|
+
assert(index);
|
812
|
+
return index->index_file_path;
|
813
|
+
}
|
814
|
+
|
508
815
|
int git_index_write_tree(git_oid *oid, git_index *index)
|
509
816
|
{
|
510
817
|
git_repository *repo;
|
@@ -515,12 +822,13 @@ int git_index_write_tree(git_oid *oid, git_index *index)
|
|
515
822
|
|
516
823
|
if (repo == NULL)
|
517
824
|
return create_index_error(-1, "Failed to write tree. "
|
518
|
-
"
|
825
|
+
"the index file is not backed up by an existing repository");
|
519
826
|
|
520
827
|
return git_tree__write_index(oid, index, repo);
|
521
828
|
}
|
522
829
|
|
523
|
-
int git_index_write_tree_to(
|
830
|
+
int git_index_write_tree_to(
|
831
|
+
git_oid *oid, git_index *index, git_repository *repo)
|
524
832
|
{
|
525
833
|
assert(oid && index && repo);
|
526
834
|
return git_tree__write_index(oid, index, repo);
|
@@ -543,99 +851,172 @@ const git_index_entry *git_index_get_byindex(
|
|
543
851
|
const git_index_entry *git_index_get_bypath(
|
544
852
|
git_index *index, const char *path, int stage)
|
545
853
|
{
|
854
|
+
git_index_entry key = {{ 0 }};
|
546
855
|
size_t pos;
|
547
856
|
|
548
857
|
assert(index);
|
549
858
|
|
550
|
-
|
859
|
+
key.path = path;
|
860
|
+
GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
|
551
861
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
862
|
+
LOOKUP_IN_MAP(pos, index, &key);
|
863
|
+
|
864
|
+
if (git_idxmap_valid_index(index->entries_map, pos))
|
865
|
+
return git_idxmap_value_at(index->entries_map, pos);
|
556
866
|
|
557
|
-
|
867
|
+
git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
|
868
|
+
return NULL;
|
558
869
|
}
|
559
870
|
|
560
|
-
void git_index_entry__init_from_stat(
|
871
|
+
void git_index_entry__init_from_stat(
|
872
|
+
git_index_entry *entry, struct stat *st, bool trust_mode)
|
561
873
|
{
|
562
|
-
entry->ctime.seconds = (
|
563
|
-
entry->mtime.seconds = (
|
564
|
-
|
565
|
-
|
874
|
+
entry->ctime.seconds = (int32_t)st->st_ctime;
|
875
|
+
entry->mtime.seconds = (int32_t)st->st_mtime;
|
876
|
+
#if defined(GIT_USE_NSEC)
|
877
|
+
entry->mtime.nanoseconds = st->st_mtime_nsec;
|
878
|
+
entry->ctime.nanoseconds = st->st_ctime_nsec;
|
879
|
+
#endif
|
566
880
|
entry->dev = st->st_rdev;
|
567
881
|
entry->ino = st->st_ino;
|
568
|
-
entry->mode =
|
882
|
+
entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
|
883
|
+
git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
|
569
884
|
entry->uid = st->st_uid;
|
570
885
|
entry->gid = st->st_gid;
|
571
|
-
entry->file_size = st->st_size;
|
886
|
+
entry->file_size = (uint32_t)st->st_size;
|
572
887
|
}
|
573
888
|
|
574
|
-
|
889
|
+
static void index_entry_adjust_namemask(
|
890
|
+
git_index_entry *entry,
|
891
|
+
size_t path_length)
|
575
892
|
{
|
576
|
-
|
577
|
-
const git_index_entry *entry_b = b;
|
893
|
+
entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK;
|
578
894
|
|
579
|
-
|
895
|
+
if (path_length < GIT_INDEX_ENTRY_NAMEMASK)
|
896
|
+
entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK;
|
897
|
+
else
|
898
|
+
entry->flags |= GIT_INDEX_ENTRY_NAMEMASK;
|
580
899
|
}
|
581
900
|
|
582
|
-
|
901
|
+
/* When `from_workdir` is true, we will validate the paths to avoid placing
|
902
|
+
* paths that are invalid for the working directory on the current filesystem
|
903
|
+
* (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This
|
904
|
+
* function will *always* prevent `.git` and directory traversal `../` from
|
905
|
+
* being added to the index.
|
906
|
+
*/
|
907
|
+
static int index_entry_create(
|
908
|
+
git_index_entry **out,
|
909
|
+
git_repository *repo,
|
910
|
+
const char *path,
|
911
|
+
struct stat *st,
|
912
|
+
bool from_workdir)
|
583
913
|
{
|
584
|
-
|
585
|
-
|
914
|
+
size_t pathlen = strlen(path), alloclen;
|
915
|
+
struct entry_internal *entry;
|
916
|
+
unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
|
917
|
+
uint16_t mode = 0;
|
918
|
+
|
919
|
+
/* always reject placing `.git` in the index and directory traversal.
|
920
|
+
* when requested, disallow platform-specific filenames and upgrade to
|
921
|
+
* the platform-specific `.git` tests (eg, `git~1`, etc).
|
922
|
+
*/
|
923
|
+
if (from_workdir)
|
924
|
+
path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
|
925
|
+
if (st)
|
926
|
+
mode = st->st_mode;
|
586
927
|
|
587
|
-
|
928
|
+
if (!git_path_isvalid(repo, path, mode, path_valid_flags)) {
|
929
|
+
git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path);
|
930
|
+
return -1;
|
931
|
+
}
|
932
|
+
|
933
|
+
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
|
934
|
+
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
|
935
|
+
entry = git__calloc(1, alloclen);
|
936
|
+
GIT_ERROR_CHECK_ALLOC(entry);
|
937
|
+
|
938
|
+
entry->pathlen = pathlen;
|
939
|
+
memcpy(entry->path, path, pathlen);
|
940
|
+
entry->entry.path = entry->path;
|
941
|
+
|
942
|
+
*out = (git_index_entry *)entry;
|
943
|
+
return 0;
|
588
944
|
}
|
589
945
|
|
590
|
-
static int index_entry_init(
|
946
|
+
static int index_entry_init(
|
947
|
+
git_index_entry **entry_out,
|
948
|
+
git_index *index,
|
949
|
+
const char *rel_path)
|
591
950
|
{
|
951
|
+
int error = 0;
|
592
952
|
git_index_entry *entry = NULL;
|
953
|
+
git_buf path = GIT_BUF_INIT;
|
593
954
|
struct stat st;
|
594
955
|
git_oid oid;
|
595
|
-
|
596
|
-
git_buf full_path = GIT_BUF_INIT;
|
597
|
-
int error;
|
956
|
+
git_repository *repo;
|
598
957
|
|
599
958
|
if (INDEX_OWNER(index) == NULL)
|
600
959
|
return create_index_error(-1,
|
601
|
-
"
|
960
|
+
"could not initialize index entry. "
|
602
961
|
"Index is not backed up by an existing repository.");
|
603
962
|
|
604
|
-
|
963
|
+
/*
|
964
|
+
* FIXME: this is duplicated with the work in
|
965
|
+
* git_blob__create_from_paths. It should accept an optional stat
|
966
|
+
* structure so we can pass in the one we have to do here.
|
967
|
+
*/
|
968
|
+
repo = INDEX_OWNER(index);
|
969
|
+
if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
|
970
|
+
return GIT_EBAREREPO;
|
971
|
+
|
972
|
+
if (git_buf_joinpath(&path, git_repository_workdir(repo), rel_path) < 0)
|
973
|
+
return -1;
|
605
974
|
|
606
|
-
|
607
|
-
|
608
|
-
"Could not initialize index entry. Repository is bare");
|
975
|
+
error = git_path_lstat(path.ptr, &st);
|
976
|
+
git_buf_dispose(&path);
|
609
977
|
|
610
|
-
if (
|
978
|
+
if (error < 0)
|
611
979
|
return error;
|
612
980
|
|
613
|
-
if ((
|
614
|
-
|
981
|
+
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0)
|
982
|
+
return -1;
|
983
|
+
|
984
|
+
/* write the blob to disk and get the oid and stat info */
|
985
|
+
error = git_blob__create_from_paths(
|
986
|
+
&oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true);
|
987
|
+
|
988
|
+
if (error < 0) {
|
989
|
+
index_entry_free(entry);
|
615
990
|
return error;
|
616
991
|
}
|
617
992
|
|
618
|
-
|
993
|
+
entry->id = oid;
|
994
|
+
git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
|
619
995
|
|
620
|
-
|
621
|
-
|
622
|
-
|
996
|
+
*entry_out = (git_index_entry *)entry;
|
997
|
+
return 0;
|
998
|
+
}
|
623
999
|
|
624
|
-
|
625
|
-
|
626
|
-
|
1000
|
+
static git_index_reuc_entry *reuc_entry_alloc(const char *path)
|
1001
|
+
{
|
1002
|
+
size_t pathlen = strlen(path),
|
1003
|
+
structlen = sizeof(struct reuc_entry_internal),
|
1004
|
+
alloclen;
|
1005
|
+
struct reuc_entry_internal *entry;
|
627
1006
|
|
628
|
-
|
629
|
-
|
1007
|
+
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
|
1008
|
+
GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
|
1009
|
+
return NULL;
|
630
1010
|
|
631
|
-
|
1011
|
+
entry = git__calloc(1, alloclen);
|
1012
|
+
if (!entry)
|
1013
|
+
return NULL;
|
632
1014
|
|
633
|
-
entry->
|
634
|
-
entry->path
|
635
|
-
|
1015
|
+
entry->pathlen = pathlen;
|
1016
|
+
memcpy(entry->path, path, pathlen);
|
1017
|
+
entry->entry.path = entry->path;
|
636
1018
|
|
637
|
-
|
638
|
-
return 0;
|
1019
|
+
return (git_index_reuc_entry *)entry;
|
639
1020
|
}
|
640
1021
|
|
641
1022
|
static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
|
@@ -648,103 +1029,392 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
|
|
648
1029
|
|
649
1030
|
assert(reuc_out && path);
|
650
1031
|
|
651
|
-
*reuc_out =
|
652
|
-
|
653
|
-
reuc = git__calloc(1, sizeof(git_index_reuc_entry));
|
654
|
-
GITERR_CHECK_ALLOC(reuc);
|
655
|
-
|
656
|
-
reuc->path = git__strdup(path);
|
657
|
-
if (reuc->path == NULL)
|
658
|
-
return -1;
|
1032
|
+
*reuc_out = reuc = reuc_entry_alloc(path);
|
1033
|
+
GIT_ERROR_CHECK_ALLOC(reuc);
|
659
1034
|
|
660
|
-
if ((reuc->mode[0] = ancestor_mode) > 0)
|
1035
|
+
if ((reuc->mode[0] = ancestor_mode) > 0) {
|
1036
|
+
assert(ancestor_oid);
|
661
1037
|
git_oid_cpy(&reuc->oid[0], ancestor_oid);
|
1038
|
+
}
|
662
1039
|
|
663
|
-
if ((reuc->mode[1] = our_mode) > 0)
|
1040
|
+
if ((reuc->mode[1] = our_mode) > 0) {
|
1041
|
+
assert(our_oid);
|
664
1042
|
git_oid_cpy(&reuc->oid[1], our_oid);
|
1043
|
+
}
|
665
1044
|
|
666
|
-
if ((reuc->mode[2] = their_mode) > 0)
|
1045
|
+
if ((reuc->mode[2] = their_mode) > 0) {
|
1046
|
+
assert(their_oid);
|
667
1047
|
git_oid_cpy(&reuc->oid[2], their_oid);
|
1048
|
+
}
|
668
1049
|
|
669
|
-
*reuc_out = reuc;
|
670
1050
|
return 0;
|
671
1051
|
}
|
672
1052
|
|
673
|
-
static void
|
1053
|
+
static void index_entry_cpy(
|
1054
|
+
git_index_entry *tgt,
|
1055
|
+
const git_index_entry *src)
|
674
1056
|
{
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
git__free(reuc->path);
|
679
|
-
git__free(reuc);
|
1057
|
+
const char *tgt_path = tgt->path;
|
1058
|
+
memcpy(tgt, src, sizeof(*tgt));
|
1059
|
+
tgt->path = tgt_path;
|
680
1060
|
}
|
681
1061
|
|
682
|
-
static
|
1062
|
+
static int index_entry_dup(
|
1063
|
+
git_index_entry **out,
|
1064
|
+
git_index *index,
|
1065
|
+
const git_index_entry *src)
|
683
1066
|
{
|
684
|
-
|
685
|
-
|
686
|
-
entry = git__malloc(sizeof(git_index_entry));
|
687
|
-
if (!entry)
|
688
|
-
return NULL;
|
689
|
-
|
690
|
-
memcpy(entry, source_entry, sizeof(git_index_entry));
|
691
|
-
|
692
|
-
/* duplicate the path string so we own it */
|
693
|
-
entry->path = git__strdup(entry->path);
|
694
|
-
if (!entry->path)
|
695
|
-
return NULL;
|
1067
|
+
if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
|
1068
|
+
return -1;
|
696
1069
|
|
697
|
-
|
1070
|
+
index_entry_cpy(*out, src);
|
1071
|
+
return 0;
|
698
1072
|
}
|
699
1073
|
|
700
|
-
static void
|
1074
|
+
static void index_entry_cpy_nocache(
|
1075
|
+
git_index_entry *tgt,
|
1076
|
+
const git_index_entry *src)
|
701
1077
|
{
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
1078
|
+
git_oid_cpy(&tgt->id, &src->id);
|
1079
|
+
tgt->mode = src->mode;
|
1080
|
+
tgt->flags = src->flags;
|
1081
|
+
tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS);
|
706
1082
|
}
|
707
1083
|
|
708
|
-
static int
|
1084
|
+
static int index_entry_dup_nocache(
|
1085
|
+
git_index_entry **out,
|
1086
|
+
git_index *index,
|
1087
|
+
const git_index_entry *src)
|
709
1088
|
{
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
assert(index && entry && entry->path != NULL);
|
714
|
-
|
715
|
-
/* make sure that the path length flag is correct */
|
716
|
-
path_length = strlen(entry->path);
|
717
|
-
|
718
|
-
entry->flags &= ~GIT_IDXENTRY_NAMEMASK;
|
1089
|
+
if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
|
1090
|
+
return -1;
|
719
1091
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
entry->flags |= GIT_IDXENTRY_NAMEMASK;
|
1092
|
+
index_entry_cpy_nocache(*out, src);
|
1093
|
+
return 0;
|
1094
|
+
}
|
724
1095
|
|
725
|
-
|
726
|
-
|
727
|
-
|
1096
|
+
static int has_file_name(git_index *index,
|
1097
|
+
const git_index_entry *entry, size_t pos, int ok_to_replace)
|
1098
|
+
{
|
1099
|
+
size_t len = strlen(entry->path);
|
1100
|
+
int stage = GIT_INDEX_ENTRY_STAGE(entry);
|
1101
|
+
const char *name = entry->path;
|
728
1102
|
|
729
|
-
|
730
|
-
|
731
|
-
}
|
1103
|
+
while (pos < index->entries.length) {
|
1104
|
+
struct entry_internal *p = index->entries.contents[pos++];
|
732
1105
|
|
733
|
-
|
734
|
-
|
1106
|
+
if (len >= p->pathlen)
|
1107
|
+
break;
|
1108
|
+
if (memcmp(name, p->path, len))
|
1109
|
+
break;
|
1110
|
+
if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage)
|
1111
|
+
continue;
|
1112
|
+
if (p->path[len] != '/')
|
1113
|
+
continue;
|
1114
|
+
if (!ok_to_replace)
|
1115
|
+
return -1;
|
1116
|
+
|
1117
|
+
if (index_remove_entry(index, --pos) < 0)
|
1118
|
+
break;
|
1119
|
+
}
|
1120
|
+
return 0;
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
/*
|
1124
|
+
* Do we have another file with a pathname that is a proper
|
1125
|
+
* subset of the name we're trying to add?
|
1126
|
+
*/
|
1127
|
+
static int has_dir_name(git_index *index,
|
1128
|
+
const git_index_entry *entry, int ok_to_replace)
|
1129
|
+
{
|
1130
|
+
int stage = GIT_INDEX_ENTRY_STAGE(entry);
|
1131
|
+
const char *name = entry->path;
|
1132
|
+
const char *slash = name + strlen(name);
|
1133
|
+
|
1134
|
+
for (;;) {
|
1135
|
+
size_t len, pos;
|
1136
|
+
|
1137
|
+
for (;;) {
|
1138
|
+
if (*--slash == '/')
|
1139
|
+
break;
|
1140
|
+
if (slash <= entry->path)
|
1141
|
+
return 0;
|
1142
|
+
}
|
1143
|
+
len = slash - name;
|
1144
|
+
|
1145
|
+
if (!index_find(&pos, index, name, len, stage)) {
|
1146
|
+
if (!ok_to_replace)
|
1147
|
+
return -1;
|
1148
|
+
|
1149
|
+
if (index_remove_entry(index, pos) < 0)
|
1150
|
+
break;
|
1151
|
+
continue;
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
/*
|
1155
|
+
* Trivial optimization: if we find an entry that
|
1156
|
+
* already matches the sub-directory, then we know
|
1157
|
+
* we're ok, and we can exit.
|
1158
|
+
*/
|
1159
|
+
for (; pos < index->entries.length; ++pos) {
|
1160
|
+
struct entry_internal *p = index->entries.contents[pos];
|
1161
|
+
|
1162
|
+
if (p->pathlen <= len ||
|
1163
|
+
p->path[len] != '/' ||
|
1164
|
+
memcmp(p->path, name, len))
|
1165
|
+
break; /* not our subdirectory */
|
1166
|
+
|
1167
|
+
if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage)
|
1168
|
+
return 0;
|
1169
|
+
}
|
1170
|
+
}
|
1171
|
+
|
1172
|
+
return 0;
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
static int check_file_directory_collision(git_index *index,
|
1176
|
+
git_index_entry *entry, size_t pos, int ok_to_replace)
|
1177
|
+
{
|
1178
|
+
if (has_file_name(index, entry, pos, ok_to_replace) < 0 ||
|
1179
|
+
has_dir_name(index, entry, ok_to_replace) < 0) {
|
1180
|
+
git_error_set(GIT_ERROR_INDEX,
|
1181
|
+
"'%s' appears as both a file and a directory", entry->path);
|
1182
|
+
return -1;
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
return 0;
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
static int canonicalize_directory_path(
|
1189
|
+
git_index *index,
|
1190
|
+
git_index_entry *entry,
|
1191
|
+
git_index_entry *existing)
|
1192
|
+
{
|
1193
|
+
const git_index_entry *match, *best = NULL;
|
1194
|
+
char *search, *sep;
|
1195
|
+
size_t pos, search_len, best_len;
|
1196
|
+
|
1197
|
+
if (!index->ignore_case)
|
1198
|
+
return 0;
|
1199
|
+
|
1200
|
+
/* item already exists in the index, simply re-use the existing case */
|
1201
|
+
if (existing) {
|
1202
|
+
memcpy((char *)entry->path, existing->path, strlen(existing->path));
|
1203
|
+
return 0;
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
/* nothing to do */
|
1207
|
+
if (strchr(entry->path, '/') == NULL)
|
1208
|
+
return 0;
|
1209
|
+
|
1210
|
+
if ((search = git__strdup(entry->path)) == NULL)
|
1211
|
+
return -1;
|
1212
|
+
|
1213
|
+
/* starting at the parent directory and descending to the root, find the
|
1214
|
+
* common parent directory.
|
735
1215
|
*/
|
736
|
-
|
737
|
-
|
1216
|
+
while (!best && (sep = strrchr(search, '/'))) {
|
1217
|
+
sep[1] = '\0';
|
1218
|
+
|
1219
|
+
search_len = strlen(search);
|
738
1220
|
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
1221
|
+
git_vector_bsearch2(
|
1222
|
+
&pos, &index->entries, index->entries_search_path, search);
|
1223
|
+
|
1224
|
+
while ((match = git_vector_get(&index->entries, pos))) {
|
1225
|
+
if (GIT_INDEX_ENTRY_STAGE(match) != 0) {
|
1226
|
+
/* conflicts do not contribute to canonical paths */
|
1227
|
+
} else if (strncmp(search, match->path, search_len) == 0) {
|
1228
|
+
/* prefer an exact match to the input filename */
|
1229
|
+
best = match;
|
1230
|
+
best_len = search_len;
|
1231
|
+
break;
|
1232
|
+
} else if (strncasecmp(search, match->path, search_len) == 0) {
|
1233
|
+
/* continue walking, there may be a path with an exact
|
1234
|
+
* (case sensitive) match later in the index, but use this
|
1235
|
+
* as the best match until that happens.
|
1236
|
+
*/
|
1237
|
+
if (!best) {
|
1238
|
+
best = match;
|
1239
|
+
best_len = search_len;
|
1240
|
+
}
|
1241
|
+
} else {
|
1242
|
+
break;
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
pos++;
|
1246
|
+
}
|
744
1247
|
|
1248
|
+
sep[0] = '\0';
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
if (best)
|
1252
|
+
memcpy((char *)entry->path, best->path, best_len);
|
1253
|
+
|
1254
|
+
git__free(search);
|
745
1255
|
return 0;
|
746
1256
|
}
|
747
1257
|
|
1258
|
+
static int index_no_dups(void **old, void *new)
|
1259
|
+
{
|
1260
|
+
const git_index_entry *entry = new;
|
1261
|
+
GIT_UNUSED(old);
|
1262
|
+
git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d",
|
1263
|
+
entry->path, GIT_INDEX_ENTRY_STAGE(entry));
|
1264
|
+
return GIT_EEXISTS;
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
static void index_existing_and_best(
|
1268
|
+
git_index_entry **existing,
|
1269
|
+
size_t *existing_position,
|
1270
|
+
git_index_entry **best,
|
1271
|
+
git_index *index,
|
1272
|
+
const git_index_entry *entry)
|
1273
|
+
{
|
1274
|
+
git_index_entry *e;
|
1275
|
+
size_t pos;
|
1276
|
+
int error;
|
1277
|
+
|
1278
|
+
error = index_find(&pos,
|
1279
|
+
index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry));
|
1280
|
+
|
1281
|
+
if (error == 0) {
|
1282
|
+
*existing = index->entries.contents[pos];
|
1283
|
+
*existing_position = pos;
|
1284
|
+
*best = index->entries.contents[pos];
|
1285
|
+
return;
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
*existing = NULL;
|
1289
|
+
*existing_position = 0;
|
1290
|
+
*best = NULL;
|
1291
|
+
|
1292
|
+
if (GIT_INDEX_ENTRY_STAGE(entry) == 0) {
|
1293
|
+
for (; pos < index->entries.length; pos++) {
|
1294
|
+
int (*strcomp)(const char *a, const char *b) =
|
1295
|
+
index->ignore_case ? git__strcasecmp : git__strcmp;
|
1296
|
+
|
1297
|
+
e = index->entries.contents[pos];
|
1298
|
+
|
1299
|
+
if (strcomp(entry->path, e->path) != 0)
|
1300
|
+
break;
|
1301
|
+
|
1302
|
+
if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) {
|
1303
|
+
*best = e;
|
1304
|
+
continue;
|
1305
|
+
} else {
|
1306
|
+
*best = e;
|
1307
|
+
break;
|
1308
|
+
}
|
1309
|
+
}
|
1310
|
+
}
|
1311
|
+
}
|
1312
|
+
|
1313
|
+
/* index_insert takes ownership of the new entry - if it can't insert
|
1314
|
+
* it, then it will return an error **and also free the entry**. When
|
1315
|
+
* it replaces an existing entry, it will update the entry_ptr with the
|
1316
|
+
* actual entry in the index (and free the passed in one).
|
1317
|
+
*
|
1318
|
+
* trust_path is whether we use the given path, or whether (on case
|
1319
|
+
* insensitive systems only) we try to canonicalize the given path to
|
1320
|
+
* be within an existing directory.
|
1321
|
+
*
|
1322
|
+
* trust_mode is whether we trust the mode in entry_ptr.
|
1323
|
+
*
|
1324
|
+
* trust_id is whether we trust the id or it should be validated.
|
1325
|
+
*/
|
1326
|
+
static int index_insert(
|
1327
|
+
git_index *index,
|
1328
|
+
git_index_entry **entry_ptr,
|
1329
|
+
int replace,
|
1330
|
+
bool trust_path,
|
1331
|
+
bool trust_mode,
|
1332
|
+
bool trust_id)
|
1333
|
+
{
|
1334
|
+
git_index_entry *existing, *best, *entry;
|
1335
|
+
size_t path_length, position;
|
1336
|
+
int error;
|
1337
|
+
|
1338
|
+
assert(index && entry_ptr);
|
1339
|
+
|
1340
|
+
entry = *entry_ptr;
|
1341
|
+
|
1342
|
+
/* Make sure that the path length flag is correct */
|
1343
|
+
path_length = ((struct entry_internal *)entry)->pathlen;
|
1344
|
+
index_entry_adjust_namemask(entry, path_length);
|
1345
|
+
|
1346
|
+
/* This entry is now up-to-date and should not be checked for raciness */
|
1347
|
+
entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
|
1348
|
+
|
1349
|
+
git_vector_sort(&index->entries);
|
1350
|
+
|
1351
|
+
/*
|
1352
|
+
* Look if an entry with this path already exists, either staged, or (if
|
1353
|
+
* this entry is a regular staged item) as the "ours" side of a conflict.
|
1354
|
+
*/
|
1355
|
+
index_existing_and_best(&existing, &position, &best, index, entry);
|
1356
|
+
|
1357
|
+
/* Update the file mode */
|
1358
|
+
entry->mode = trust_mode ?
|
1359
|
+
git_index__create_mode(entry->mode) :
|
1360
|
+
index_merge_mode(index, best, entry->mode);
|
1361
|
+
|
1362
|
+
/* Canonicalize the directory name */
|
1363
|
+
if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0)
|
1364
|
+
goto out;
|
1365
|
+
|
1366
|
+
/* Ensure that the given id exists (unless it's a submodule) */
|
1367
|
+
if (!trust_id && INDEX_OWNER(index) &&
|
1368
|
+
(entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) {
|
1369
|
+
|
1370
|
+
if (!git_object__is_valid(INDEX_OWNER(index), &entry->id,
|
1371
|
+
git_object__type_from_filemode(entry->mode))) {
|
1372
|
+
error = -1;
|
1373
|
+
goto out;
|
1374
|
+
}
|
1375
|
+
}
|
1376
|
+
|
1377
|
+
/* Look for tree / blob name collisions, removing conflicts if requested */
|
1378
|
+
if ((error = check_file_directory_collision(index, entry, position, replace)) < 0)
|
1379
|
+
goto out;
|
1380
|
+
|
1381
|
+
/*
|
1382
|
+
* If we are replacing an existing item, overwrite the existing entry
|
1383
|
+
* and return it in place of the passed in one.
|
1384
|
+
*/
|
1385
|
+
if (existing) {
|
1386
|
+
if (replace) {
|
1387
|
+
index_entry_cpy(existing, entry);
|
1388
|
+
|
1389
|
+
if (trust_path)
|
1390
|
+
memcpy((char *)existing->path, entry->path, strlen(entry->path));
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
index_entry_free(entry);
|
1394
|
+
*entry_ptr = existing;
|
1395
|
+
} else {
|
1396
|
+
/*
|
1397
|
+
* If replace is not requested or no existing entry exists, insert
|
1398
|
+
* at the sorted position. (Since we re-sort after each insert to
|
1399
|
+
* check for dups, this is actually cheaper in the long run.)
|
1400
|
+
*/
|
1401
|
+
if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0)
|
1402
|
+
goto out;
|
1403
|
+
|
1404
|
+
INSERT_IN_MAP(index, entry, &error);
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
index->dirty = 1;
|
1408
|
+
|
1409
|
+
out:
|
1410
|
+
if (error < 0) {
|
1411
|
+
index_entry_free(*entry_ptr);
|
1412
|
+
*entry_ptr = NULL;
|
1413
|
+
}
|
1414
|
+
|
1415
|
+
return error;
|
1416
|
+
}
|
1417
|
+
|
748
1418
|
static int index_conflict_to_reuc(git_index *index, const char *path)
|
749
1419
|
{
|
750
1420
|
const git_index_entry *conflict_entries[3];
|
@@ -760,9 +1430,9 @@ static int index_conflict_to_reuc(git_index *index, const char *path)
|
|
760
1430
|
our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode;
|
761
1431
|
their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode;
|
762
1432
|
|
763
|
-
ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->
|
764
|
-
our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->
|
765
|
-
their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->
|
1433
|
+
ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id;
|
1434
|
+
our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id;
|
1435
|
+
their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id;
|
766
1436
|
|
767
1437
|
if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid,
|
768
1438
|
our_mode, our_oid, their_mode, their_oid)) >= 0)
|
@@ -771,6 +1441,101 @@ static int index_conflict_to_reuc(git_index *index, const char *path)
|
|
771
1441
|
return ret;
|
772
1442
|
}
|
773
1443
|
|
1444
|
+
GIT_INLINE(bool) is_file_or_link(const int filemode)
|
1445
|
+
{
|
1446
|
+
return (filemode == GIT_FILEMODE_BLOB ||
|
1447
|
+
filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
|
1448
|
+
filemode == GIT_FILEMODE_LINK);
|
1449
|
+
}
|
1450
|
+
|
1451
|
+
GIT_INLINE(bool) valid_filemode(const int filemode)
|
1452
|
+
{
|
1453
|
+
return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT);
|
1454
|
+
}
|
1455
|
+
|
1456
|
+
int git_index_add_frombuffer(
|
1457
|
+
git_index *index, const git_index_entry *source_entry,
|
1458
|
+
const void *buffer, size_t len)
|
1459
|
+
{
|
1460
|
+
git_index_entry *entry = NULL;
|
1461
|
+
int error = 0;
|
1462
|
+
git_oid id;
|
1463
|
+
|
1464
|
+
assert(index && source_entry->path);
|
1465
|
+
|
1466
|
+
if (INDEX_OWNER(index) == NULL)
|
1467
|
+
return create_index_error(-1,
|
1468
|
+
"could not initialize index entry. "
|
1469
|
+
"Index is not backed up by an existing repository.");
|
1470
|
+
|
1471
|
+
if (!is_file_or_link(source_entry->mode)) {
|
1472
|
+
git_error_set(GIT_ERROR_INDEX, "invalid filemode");
|
1473
|
+
return -1;
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
if (index_entry_dup(&entry, index, source_entry) < 0)
|
1477
|
+
return -1;
|
1478
|
+
|
1479
|
+
error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
|
1480
|
+
if (error < 0) {
|
1481
|
+
index_entry_free(entry);
|
1482
|
+
return error;
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
git_oid_cpy(&entry->id, &id);
|
1486
|
+
entry->file_size = len;
|
1487
|
+
|
1488
|
+
if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
|
1489
|
+
return error;
|
1490
|
+
|
1491
|
+
/* Adding implies conflict was resolved, move conflict entries to REUC */
|
1492
|
+
if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND)
|
1493
|
+
return error;
|
1494
|
+
|
1495
|
+
git_tree_cache_invalidate_path(index->tree, entry->path);
|
1496
|
+
return 0;
|
1497
|
+
}
|
1498
|
+
|
1499
|
+
static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
|
1500
|
+
{
|
1501
|
+
git_repository *sub;
|
1502
|
+
git_buf abspath = GIT_BUF_INIT;
|
1503
|
+
git_repository *repo = INDEX_OWNER(index);
|
1504
|
+
git_reference *head;
|
1505
|
+
git_index_entry *entry;
|
1506
|
+
struct stat st;
|
1507
|
+
int error;
|
1508
|
+
|
1509
|
+
if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
|
1510
|
+
return error;
|
1511
|
+
|
1512
|
+
if ((error = p_stat(abspath.ptr, &st)) < 0) {
|
1513
|
+
git_error_set(GIT_ERROR_OS, "failed to stat repository dir");
|
1514
|
+
return -1;
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0)
|
1518
|
+
return -1;
|
1519
|
+
|
1520
|
+
git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
|
1521
|
+
|
1522
|
+
if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
|
1523
|
+
return error;
|
1524
|
+
|
1525
|
+
if ((error = git_repository_head(&head, sub)) < 0)
|
1526
|
+
return error;
|
1527
|
+
|
1528
|
+
git_oid_cpy(&entry->id, git_reference_target(head));
|
1529
|
+
entry->mode = GIT_FILEMODE_COMMIT;
|
1530
|
+
|
1531
|
+
git_reference_free(head);
|
1532
|
+
git_repository_free(sub);
|
1533
|
+
git_buf_dispose(&abspath);
|
1534
|
+
|
1535
|
+
*out = entry;
|
1536
|
+
return 0;
|
1537
|
+
}
|
1538
|
+
|
774
1539
|
int git_index_add_bypath(git_index *index, const char *path)
|
775
1540
|
{
|
776
1541
|
git_index_entry *entry = NULL;
|
@@ -778,20 +1543,50 @@ int git_index_add_bypath(git_index *index, const char *path)
|
|
778
1543
|
|
779
1544
|
assert(index && path);
|
780
1545
|
|
781
|
-
if ((ret = index_entry_init(&entry, index, path))
|
782
|
-
|
783
|
-
|
1546
|
+
if ((ret = index_entry_init(&entry, index, path)) == 0)
|
1547
|
+
ret = index_insert(index, &entry, 1, false, false, true);
|
1548
|
+
|
1549
|
+
/* If we were given a directory, let's see if it's a submodule */
|
1550
|
+
if (ret < 0 && ret != GIT_EDIRECTORY)
|
1551
|
+
return ret;
|
1552
|
+
|
1553
|
+
if (ret == GIT_EDIRECTORY) {
|
1554
|
+
git_submodule *sm;
|
1555
|
+
git_error_state err;
|
1556
|
+
|
1557
|
+
git_error_state_capture(&err, ret);
|
1558
|
+
|
1559
|
+
ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
|
1560
|
+
if (ret == GIT_ENOTFOUND)
|
1561
|
+
return git_error_state_restore(&err);
|
1562
|
+
|
1563
|
+
git_error_state_free(&err);
|
1564
|
+
|
1565
|
+
/*
|
1566
|
+
* EEXISTS means that there is a repository at that path, but it's not known
|
1567
|
+
* as a submodule. We add its HEAD as an entry and don't register it.
|
1568
|
+
*/
|
1569
|
+
if (ret == GIT_EEXISTS) {
|
1570
|
+
if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
|
1571
|
+
return ret;
|
1572
|
+
|
1573
|
+
if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0)
|
1574
|
+
return ret;
|
1575
|
+
} else if (ret < 0) {
|
1576
|
+
return ret;
|
1577
|
+
} else {
|
1578
|
+
ret = git_submodule_add_to_index(sm, false);
|
1579
|
+
git_submodule_free(sm);
|
1580
|
+
return ret;
|
1581
|
+
}
|
1582
|
+
}
|
784
1583
|
|
785
1584
|
/* Adding implies conflict was resolved, move conflict entries to REUC */
|
786
1585
|
if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
|
787
|
-
|
1586
|
+
return ret;
|
788
1587
|
|
789
1588
|
git_tree_cache_invalidate_path(index->tree, entry->path);
|
790
1589
|
return 0;
|
791
|
-
|
792
|
-
on_error:
|
793
|
-
index_entry_free(entry);
|
794
|
-
return ret;
|
795
1590
|
}
|
796
1591
|
|
797
1592
|
int git_index_remove_bypath(git_index *index, const char *path)
|
@@ -806,22 +1601,68 @@ int git_index_remove_bypath(git_index *index, const char *path)
|
|
806
1601
|
ret != GIT_ENOTFOUND))
|
807
1602
|
return ret;
|
808
1603
|
|
1604
|
+
if (ret == GIT_ENOTFOUND)
|
1605
|
+
git_error_clear();
|
1606
|
+
|
809
1607
|
return 0;
|
810
1608
|
}
|
811
1609
|
|
1610
|
+
int git_index__fill(git_index *index, const git_vector *source_entries)
|
1611
|
+
{
|
1612
|
+
const git_index_entry *source_entry = NULL;
|
1613
|
+
size_t i;
|
1614
|
+
int ret = 0;
|
1615
|
+
|
1616
|
+
assert(index);
|
1617
|
+
|
1618
|
+
if (!source_entries->length)
|
1619
|
+
return 0;
|
1620
|
+
|
1621
|
+
git_vector_size_hint(&index->entries, source_entries->length);
|
1622
|
+
git_idxmap_resize(index->entries_map, (size_t)(source_entries->length * 1.3));
|
1623
|
+
|
1624
|
+
git_vector_foreach(source_entries, i, source_entry) {
|
1625
|
+
git_index_entry *entry = NULL;
|
1626
|
+
|
1627
|
+
if ((ret = index_entry_dup(&entry, index, source_entry)) < 0)
|
1628
|
+
break;
|
1629
|
+
|
1630
|
+
index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen);
|
1631
|
+
entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
|
1632
|
+
entry->mode = git_index__create_mode(entry->mode);
|
1633
|
+
|
1634
|
+
if ((ret = git_vector_insert(&index->entries, entry)) < 0)
|
1635
|
+
break;
|
1636
|
+
|
1637
|
+
INSERT_IN_MAP(index, entry, &ret);
|
1638
|
+
if (ret < 0)
|
1639
|
+
break;
|
1640
|
+
|
1641
|
+
index->dirty = 1;
|
1642
|
+
}
|
1643
|
+
|
1644
|
+
if (!ret)
|
1645
|
+
git_vector_sort(&index->entries);
|
1646
|
+
|
1647
|
+
return ret;
|
1648
|
+
}
|
1649
|
+
|
1650
|
+
|
812
1651
|
int git_index_add(git_index *index, const git_index_entry *source_entry)
|
813
1652
|
{
|
814
1653
|
git_index_entry *entry = NULL;
|
815
1654
|
int ret;
|
816
1655
|
|
817
|
-
|
818
|
-
|
1656
|
+
assert(index && source_entry && source_entry->path);
|
1657
|
+
|
1658
|
+
if (!valid_filemode(source_entry->mode)) {
|
1659
|
+
git_error_set(GIT_ERROR_INDEX, "invalid entry mode");
|
819
1660
|
return -1;
|
1661
|
+
}
|
820
1662
|
|
821
|
-
if ((ret =
|
822
|
-
|
1663
|
+
if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
|
1664
|
+
(ret = index_insert(index, &entry, 1, true, true, false)) < 0)
|
823
1665
|
return ret;
|
824
|
-
}
|
825
1666
|
|
826
1667
|
git_tree_cache_invalidate_path(index->tree, entry->path);
|
827
1668
|
return 0;
|
@@ -829,26 +1670,22 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
|
|
829
1670
|
|
830
1671
|
int git_index_remove(git_index *index, const char *path, int stage)
|
831
1672
|
{
|
832
|
-
size_t position;
|
833
1673
|
int error;
|
834
|
-
|
835
|
-
|
836
|
-
git_vector_sort(&index->entries);
|
1674
|
+
size_t position;
|
1675
|
+
git_index_entry remove_key = {{ 0 }};
|
837
1676
|
|
838
|
-
|
839
|
-
|
840
|
-
path, stage);
|
841
|
-
return GIT_ENOTFOUND;
|
842
|
-
}
|
1677
|
+
remove_key.path = path;
|
1678
|
+
GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage);
|
843
1679
|
|
844
|
-
|
845
|
-
if (entry != NULL)
|
846
|
-
git_tree_cache_invalidate_path(index->tree, entry->path);
|
1680
|
+
DELETE_IN_MAP(index, &remove_key);
|
847
1681
|
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
1682
|
+
if (index_find(&position, index, path, 0, stage) < 0) {
|
1683
|
+
git_error_set(
|
1684
|
+
GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage);
|
1685
|
+
error = GIT_ENOTFOUND;
|
1686
|
+
} else {
|
1687
|
+
error = index_remove_entry(index, position);
|
1688
|
+
}
|
852
1689
|
|
853
1690
|
return error;
|
854
1691
|
}
|
@@ -860,47 +1697,52 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
|
|
860
1697
|
size_t pos;
|
861
1698
|
git_index_entry *entry;
|
862
1699
|
|
863
|
-
if (git_buf_sets(&pfx, dir)
|
864
|
-
|
1700
|
+
if (!(error = git_buf_sets(&pfx, dir)) &&
|
1701
|
+
!(error = git_path_to_dir(&pfx)))
|
1702
|
+
index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY);
|
865
1703
|
|
866
|
-
|
867
|
-
|
868
|
-
pos = git_index__prefix_position(index, pfx.ptr);
|
869
|
-
|
870
|
-
while (1) {
|
1704
|
+
while (!error) {
|
871
1705
|
entry = git_vector_get(&index->entries, pos);
|
872
1706
|
if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
|
873
1707
|
break;
|
874
1708
|
|
875
|
-
if (
|
1709
|
+
if (GIT_INDEX_ENTRY_STAGE(entry) != stage) {
|
876
1710
|
++pos;
|
877
1711
|
continue;
|
878
1712
|
}
|
879
1713
|
|
880
|
-
|
881
|
-
|
882
|
-
if ((error = git_vector_remove(&index->entries, pos)) < 0)
|
883
|
-
break;
|
884
|
-
index_entry_free(entry);
|
1714
|
+
error = index_remove_entry(index, pos);
|
885
1715
|
|
886
|
-
/* removed entry at 'pos' so we don't need to increment
|
1716
|
+
/* removed entry at 'pos' so we don't need to increment */
|
887
1717
|
}
|
888
1718
|
|
889
|
-
|
1719
|
+
git_buf_dispose(&pfx);
|
890
1720
|
|
891
1721
|
return error;
|
892
1722
|
}
|
893
1723
|
|
894
|
-
|
1724
|
+
int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
|
895
1725
|
{
|
896
|
-
|
1726
|
+
int error = 0;
|
1727
|
+
size_t pos;
|
1728
|
+
const git_index_entry *entry;
|
897
1729
|
|
898
|
-
|
1730
|
+
index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY);
|
1731
|
+
entry = git_vector_get(&index->entries, pos);
|
1732
|
+
if (!entry || git__prefixcmp(entry->path, prefix) != 0)
|
1733
|
+
error = GIT_ENOTFOUND;
|
899
1734
|
|
900
|
-
|
901
|
-
|
1735
|
+
if (!error && at_pos)
|
1736
|
+
*at_pos = pos;
|
902
1737
|
|
903
|
-
return
|
1738
|
+
return error;
|
1739
|
+
}
|
1740
|
+
|
1741
|
+
int git_index__find_pos(
|
1742
|
+
size_t *out, git_index *index, const char *path, size_t path_len, int stage)
|
1743
|
+
{
|
1744
|
+
assert(index && path);
|
1745
|
+
return index_find(out, index, path, path_len, stage);
|
904
1746
|
}
|
905
1747
|
|
906
1748
|
int git_index_find(size_t *at_pos, git_index *index, const char *path)
|
@@ -909,21 +1751,20 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
|
|
909
1751
|
|
910
1752
|
assert(index && path);
|
911
1753
|
|
912
|
-
if (git_vector_bsearch2(
|
913
|
-
|
1754
|
+
if (git_vector_bsearch2(
|
1755
|
+
&pos, &index->entries, index->entries_search_path, path) < 0) {
|
1756
|
+
git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path);
|
914
1757
|
return GIT_ENOTFOUND;
|
915
1758
|
}
|
916
1759
|
|
917
1760
|
/* Since our binary search only looked at path, we may be in the
|
918
1761
|
* middle of a list of stages.
|
919
1762
|
*/
|
920
|
-
|
921
|
-
const git_index_entry *prev = git_vector_get(&index->entries, pos-1);
|
1763
|
+
for (; pos > 0; --pos) {
|
1764
|
+
const git_index_entry *prev = git_vector_get(&index->entries, pos - 1);
|
922
1765
|
|
923
1766
|
if (index->entries_cmp_path(prev->path, path) != 0)
|
924
1767
|
break;
|
925
|
-
|
926
|
-
--pos;
|
927
1768
|
}
|
928
1769
|
|
929
1770
|
if (at_pos)
|
@@ -932,21 +1773,6 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
|
|
932
1773
|
return 0;
|
933
1774
|
}
|
934
1775
|
|
935
|
-
size_t git_index__prefix_position(git_index *index, const char *path)
|
936
|
-
{
|
937
|
-
struct entry_srch_key srch_key;
|
938
|
-
size_t pos;
|
939
|
-
|
940
|
-
srch_key.path = path;
|
941
|
-
srch_key.stage = 0;
|
942
|
-
|
943
|
-
git_vector_sort(&index->entries);
|
944
|
-
git_vector_bsearch2(
|
945
|
-
&pos, &index->entries, index->entries_search, &srch_key);
|
946
|
-
|
947
|
-
return pos;
|
948
|
-
}
|
949
|
-
|
950
1776
|
int git_index_conflict_add(git_index *index,
|
951
1777
|
const git_index_entry *ancestor_entry,
|
952
1778
|
const git_index_entry *our_entry,
|
@@ -958,21 +1784,50 @@ int git_index_conflict_add(git_index *index,
|
|
958
1784
|
|
959
1785
|
assert (index);
|
960
1786
|
|
961
|
-
if ((ancestor_entry
|
962
|
-
|
963
|
-
(
|
964
|
-
|
1787
|
+
if ((ancestor_entry &&
|
1788
|
+
(ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) ||
|
1789
|
+
(our_entry &&
|
1790
|
+
(ret = index_entry_dup(&entries[1], index, our_entry)) < 0) ||
|
1791
|
+
(their_entry &&
|
1792
|
+
(ret = index_entry_dup(&entries[2], index, their_entry)) < 0))
|
1793
|
+
goto on_error;
|
965
1794
|
|
1795
|
+
/* Validate entries */
|
1796
|
+
for (i = 0; i < 3; i++) {
|
1797
|
+
if (entries[i] && !valid_filemode(entries[i]->mode)) {
|
1798
|
+
git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry",
|
1799
|
+
i + 1);
|
1800
|
+
ret = -1;
|
1801
|
+
goto on_error;
|
1802
|
+
}
|
1803
|
+
}
|
1804
|
+
|
1805
|
+
/* Remove existing index entries for each path */
|
1806
|
+
for (i = 0; i < 3; i++) {
|
1807
|
+
if (entries[i] == NULL)
|
1808
|
+
continue;
|
1809
|
+
|
1810
|
+
if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
|
1811
|
+
if (ret != GIT_ENOTFOUND)
|
1812
|
+
goto on_error;
|
1813
|
+
|
1814
|
+
git_error_clear();
|
1815
|
+
ret = 0;
|
1816
|
+
}
|
1817
|
+
}
|
1818
|
+
|
1819
|
+
/* Add the conflict entries */
|
966
1820
|
for (i = 0; i < 3; i++) {
|
967
1821
|
if (entries[i] == NULL)
|
968
1822
|
continue;
|
969
1823
|
|
970
1824
|
/* Make sure stage is correct */
|
971
|
-
entries[i]
|
972
|
-
((i+1) << GIT_IDXENTRY_STAGESHIFT);
|
1825
|
+
GIT_INDEX_ENTRY_STAGE_SET(entries[i], i + 1);
|
973
1826
|
|
974
|
-
if ((ret = index_insert(index, entries[i], 1)) < 0)
|
1827
|
+
if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0)
|
975
1828
|
goto on_error;
|
1829
|
+
|
1830
|
+
entries[i] = NULL; /* don't free if later entry fails */
|
976
1831
|
}
|
977
1832
|
|
978
1833
|
return 0;
|
@@ -1010,7 +1865,7 @@ static int index_conflict__get_byindex(
|
|
1010
1865
|
if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
|
1011
1866
|
break;
|
1012
1867
|
|
1013
|
-
stage =
|
1868
|
+
stage = GIT_INDEX_ENTRY_STAGE(conflict_entry);
|
1014
1869
|
path = conflict_entry->path;
|
1015
1870
|
|
1016
1871
|
switch (stage) {
|
@@ -1062,56 +1917,43 @@ int git_index_conflict_get(
|
|
1062
1917
|
return 0;
|
1063
1918
|
}
|
1064
1919
|
|
1065
|
-
int
|
1920
|
+
static int index_conflict_remove(git_index *index, const char *path)
|
1066
1921
|
{
|
1067
|
-
size_t pos
|
1922
|
+
size_t pos = 0;
|
1068
1923
|
git_index_entry *conflict_entry;
|
1069
1924
|
int error = 0;
|
1070
1925
|
|
1071
|
-
|
1072
|
-
|
1073
|
-
if (git_index_find(&pos, index, path) < 0)
|
1926
|
+
if (path != NULL && git_index_find(&pos, index, path) < 0)
|
1074
1927
|
return GIT_ENOTFOUND;
|
1075
1928
|
|
1076
|
-
|
1929
|
+
while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) {
|
1077
1930
|
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
if (index->entries_cmp_path(conflict_entry->path, path) != 0)
|
1931
|
+
if (path != NULL &&
|
1932
|
+
index->entries_cmp_path(conflict_entry->path, path) != 0)
|
1082
1933
|
break;
|
1083
1934
|
|
1084
|
-
if (
|
1935
|
+
if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) {
|
1085
1936
|
pos++;
|
1086
1937
|
continue;
|
1087
1938
|
}
|
1088
1939
|
|
1089
|
-
if ((error =
|
1090
|
-
|
1091
|
-
|
1092
|
-
index_entry_free(conflict_entry);
|
1093
|
-
posmax--;
|
1940
|
+
if ((error = index_remove_entry(index, pos)) < 0)
|
1941
|
+
break;
|
1094
1942
|
}
|
1095
1943
|
|
1096
|
-
return
|
1944
|
+
return error;
|
1097
1945
|
}
|
1098
1946
|
|
1099
|
-
|
1947
|
+
int git_index_conflict_remove(git_index *index, const char *path)
|
1100
1948
|
{
|
1101
|
-
|
1102
|
-
|
1103
|
-
if (GIT_IDXENTRY_STAGE(entry) > 0) {
|
1104
|
-
index_entry_free(entry);
|
1105
|
-
return 1;
|
1106
|
-
}
|
1107
|
-
|
1108
|
-
return 0;
|
1949
|
+
assert(index && path);
|
1950
|
+
return index_conflict_remove(index, path);
|
1109
1951
|
}
|
1110
1952
|
|
1111
|
-
|
1953
|
+
int git_index_conflict_cleanup(git_index *index)
|
1112
1954
|
{
|
1113
1955
|
assert(index);
|
1114
|
-
|
1956
|
+
return index_conflict_remove(index, NULL);
|
1115
1957
|
}
|
1116
1958
|
|
1117
1959
|
int git_index_has_conflicts(const git_index *index)
|
@@ -1122,13 +1964,58 @@ int git_index_has_conflicts(const git_index *index)
|
|
1122
1964
|
assert(index);
|
1123
1965
|
|
1124
1966
|
git_vector_foreach(&index->entries, i, entry) {
|
1125
|
-
if (
|
1967
|
+
if (GIT_INDEX_ENTRY_STAGE(entry) > 0)
|
1126
1968
|
return 1;
|
1127
1969
|
}
|
1128
1970
|
|
1129
1971
|
return 0;
|
1130
1972
|
}
|
1131
1973
|
|
1974
|
+
int git_index_iterator_new(
|
1975
|
+
git_index_iterator **iterator_out,
|
1976
|
+
git_index *index)
|
1977
|
+
{
|
1978
|
+
git_index_iterator *it;
|
1979
|
+
int error;
|
1980
|
+
|
1981
|
+
assert(iterator_out && index);
|
1982
|
+
|
1983
|
+
it = git__calloc(1, sizeof(git_index_iterator));
|
1984
|
+
GIT_ERROR_CHECK_ALLOC(it);
|
1985
|
+
|
1986
|
+
if ((error = git_index_snapshot_new(&it->snap, index)) < 0) {
|
1987
|
+
git__free(it);
|
1988
|
+
return error;
|
1989
|
+
}
|
1990
|
+
|
1991
|
+
it->index = index;
|
1992
|
+
|
1993
|
+
*iterator_out = it;
|
1994
|
+
return 0;
|
1995
|
+
}
|
1996
|
+
|
1997
|
+
int git_index_iterator_next(
|
1998
|
+
const git_index_entry **out,
|
1999
|
+
git_index_iterator *it)
|
2000
|
+
{
|
2001
|
+
assert(out && it);
|
2002
|
+
|
2003
|
+
if (it->cur >= git_vector_length(&it->snap))
|
2004
|
+
return GIT_ITEROVER;
|
2005
|
+
|
2006
|
+
*out = (git_index_entry *)git_vector_get(&it->snap, it->cur++);
|
2007
|
+
return 0;
|
2008
|
+
}
|
2009
|
+
|
2010
|
+
void git_index_iterator_free(git_index_iterator *it)
|
2011
|
+
{
|
2012
|
+
if (it == NULL)
|
2013
|
+
return;
|
2014
|
+
|
2015
|
+
git_index_snapshot_release(&it->snap, it->index);
|
2016
|
+
git__free(it);
|
2017
|
+
}
|
2018
|
+
|
1132
2019
|
int git_index_conflict_iterator_new(
|
1133
2020
|
git_index_conflict_iterator **iterator_out,
|
1134
2021
|
git_index *index)
|
@@ -1138,7 +2025,7 @@ int git_index_conflict_iterator_new(
|
|
1138
2025
|
assert(iterator_out && index);
|
1139
2026
|
|
1140
2027
|
it = git__calloc(1, sizeof(git_index_conflict_iterator));
|
1141
|
-
|
2028
|
+
GIT_ERROR_CHECK_ALLOC(it);
|
1142
2029
|
|
1143
2030
|
it->index = index;
|
1144
2031
|
|
@@ -1164,7 +2051,7 @@ int git_index_conflict_next(
|
|
1164
2051
|
while (iterator->cur < iterator->index->entries.length) {
|
1165
2052
|
entry = git_index_get_byindex(iterator->index, iterator->cur);
|
1166
2053
|
|
1167
|
-
if (
|
2054
|
+
if (git_index_entry_is_conflict(entry)) {
|
1168
2055
|
if ((len = index_conflict__get_byindex(
|
1169
2056
|
ancestor_out,
|
1170
2057
|
our_out,
|
@@ -1191,10 +2078,10 @@ void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
|
|
1191
2078
|
git__free(iterator);
|
1192
2079
|
}
|
1193
2080
|
|
1194
|
-
|
2081
|
+
size_t git_index_name_entrycount(git_index *index)
|
1195
2082
|
{
|
1196
2083
|
assert(index);
|
1197
|
-
return
|
2084
|
+
return index->names.length;
|
1198
2085
|
}
|
1199
2086
|
|
1200
2087
|
const git_index_name_entry *git_index_name_get_byindex(
|
@@ -1206,32 +2093,37 @@ const git_index_name_entry *git_index_name_get_byindex(
|
|
1206
2093
|
return git_vector_get(&index->names, n);
|
1207
2094
|
}
|
1208
2095
|
|
2096
|
+
static void index_name_entry_free(git_index_name_entry *ne)
|
2097
|
+
{
|
2098
|
+
if (!ne)
|
2099
|
+
return;
|
2100
|
+
git__free(ne->ancestor);
|
2101
|
+
git__free(ne->ours);
|
2102
|
+
git__free(ne->theirs);
|
2103
|
+
git__free(ne);
|
2104
|
+
}
|
2105
|
+
|
1209
2106
|
int git_index_name_add(git_index *index,
|
1210
2107
|
const char *ancestor, const char *ours, const char *theirs)
|
1211
2108
|
{
|
1212
2109
|
git_index_name_entry *conflict_name;
|
1213
2110
|
|
1214
|
-
assert
|
2111
|
+
assert((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
|
1215
2112
|
|
1216
2113
|
conflict_name = git__calloc(1, sizeof(git_index_name_entry));
|
1217
|
-
|
1218
|
-
|
1219
|
-
if (ancestor) {
|
1220
|
-
conflict_name->ancestor = git__strdup(ancestor);
|
1221
|
-
GITERR_CHECK_ALLOC(conflict_name->ancestor);
|
1222
|
-
}
|
1223
|
-
|
1224
|
-
if (ours) {
|
1225
|
-
conflict_name->ours = git__strdup(ours);
|
1226
|
-
GITERR_CHECK_ALLOC(conflict_name->ours);
|
1227
|
-
}
|
2114
|
+
GIT_ERROR_CHECK_ALLOC(conflict_name);
|
1228
2115
|
|
1229
|
-
if (
|
1230
|
-
conflict_name->
|
1231
|
-
|
2116
|
+
if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) ||
|
2117
|
+
(ours && !(conflict_name->ours = git__strdup(ours))) ||
|
2118
|
+
(theirs && !(conflict_name->theirs = git__strdup(theirs))) ||
|
2119
|
+
git_vector_insert(&index->names, conflict_name) < 0)
|
2120
|
+
{
|
2121
|
+
index_name_entry_free(conflict_name);
|
2122
|
+
return -1;
|
1232
2123
|
}
|
1233
2124
|
|
1234
|
-
|
2125
|
+
index->dirty = 1;
|
2126
|
+
return 0;
|
1235
2127
|
}
|
1236
2128
|
|
1237
2129
|
void git_index_name_clear(git_index *index)
|
@@ -1241,50 +2133,40 @@ void git_index_name_clear(git_index *index)
|
|
1241
2133
|
|
1242
2134
|
assert(index);
|
1243
2135
|
|
1244
|
-
git_vector_foreach(&index->names, i, conflict_name)
|
1245
|
-
|
1246
|
-
git__free(conflict_name->ancestor);
|
1247
|
-
|
1248
|
-
if (conflict_name->ours)
|
1249
|
-
git__free(conflict_name->ours);
|
1250
|
-
|
1251
|
-
if (conflict_name->theirs)
|
1252
|
-
git__free(conflict_name->theirs);
|
1253
|
-
|
1254
|
-
git__free(conflict_name);
|
1255
|
-
}
|
2136
|
+
git_vector_foreach(&index->names, i, conflict_name)
|
2137
|
+
index_name_entry_free(conflict_name);
|
1256
2138
|
|
1257
2139
|
git_vector_clear(&index->names);
|
2140
|
+
|
2141
|
+
index->dirty = 1;
|
1258
2142
|
}
|
1259
2143
|
|
1260
|
-
|
2144
|
+
size_t git_index_reuc_entrycount(git_index *index)
|
1261
2145
|
{
|
1262
2146
|
assert(index);
|
1263
|
-
return
|
2147
|
+
return index->reuc.length;
|
2148
|
+
}
|
2149
|
+
|
2150
|
+
static int index_reuc_on_dup(void **old, void *new)
|
2151
|
+
{
|
2152
|
+
index_entry_reuc_free(*old);
|
2153
|
+
*old = new;
|
2154
|
+
return GIT_EEXISTS;
|
1264
2155
|
}
|
1265
2156
|
|
1266
2157
|
static int index_reuc_insert(
|
1267
2158
|
git_index *index,
|
1268
|
-
git_index_reuc_entry *reuc
|
1269
|
-
int replace)
|
2159
|
+
git_index_reuc_entry *reuc)
|
1270
2160
|
{
|
1271
|
-
|
1272
|
-
size_t position;
|
2161
|
+
int res;
|
1273
2162
|
|
1274
2163
|
assert(index && reuc && reuc->path != NULL);
|
2164
|
+
assert(git_vector_is_sorted(&index->reuc));
|
1275
2165
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
if (!replace || !existing)
|
1280
|
-
return git_vector_insert(&index->reuc, reuc);
|
2166
|
+
res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
|
2167
|
+
index->dirty = 1;
|
1281
2168
|
|
1282
|
-
|
1283
|
-
git__free((*existing)->path);
|
1284
|
-
git__free(*existing);
|
1285
|
-
*existing = reuc;
|
1286
|
-
|
1287
|
-
return 0;
|
2169
|
+
return res == GIT_EEXISTS ? 0 : res;
|
1288
2170
|
}
|
1289
2171
|
|
1290
2172
|
int git_index_reuc_add(git_index *index, const char *path,
|
@@ -1297,15 +2179,13 @@ int git_index_reuc_add(git_index *index, const char *path,
|
|
1297
2179
|
|
1298
2180
|
assert(index && path);
|
1299
2181
|
|
1300
|
-
if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
|
1301
|
-
|
1302
|
-
|
2182
|
+
if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
|
2183
|
+
ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
|
2184
|
+
(error = index_reuc_insert(index, reuc)) < 0)
|
1303
2185
|
index_entry_reuc_free(reuc);
|
1304
|
-
return error;
|
1305
|
-
}
|
1306
2186
|
|
1307
2187
|
return error;
|
1308
|
-
}
|
2188
|
+
}
|
1309
2189
|
|
1310
2190
|
int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path)
|
1311
2191
|
{
|
@@ -1321,7 +2201,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
|
|
1321
2201
|
if (!index->reuc.length)
|
1322
2202
|
return NULL;
|
1323
2203
|
|
1324
|
-
|
2204
|
+
assert(git_vector_is_sorted(&index->reuc));
|
1325
2205
|
|
1326
2206
|
if (git_index_reuc_find(&pos, index, path) < 0)
|
1327
2207
|
return NULL;
|
@@ -1333,8 +2213,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex(
|
|
1333
2213
|
git_index *index, size_t n)
|
1334
2214
|
{
|
1335
2215
|
assert(index);
|
2216
|
+
assert(git_vector_is_sorted(&index->reuc));
|
1336
2217
|
|
1337
|
-
git_vector_sort(&index->reuc);
|
1338
2218
|
return git_vector_get(&index->reuc, n);
|
1339
2219
|
}
|
1340
2220
|
|
@@ -1343,7 +2223,7 @@ int git_index_reuc_remove(git_index *index, size_t position)
|
|
1343
2223
|
int error;
|
1344
2224
|
git_index_reuc_entry *reuc;
|
1345
2225
|
|
1346
|
-
|
2226
|
+
assert(git_vector_is_sorted(&index->reuc));
|
1347
2227
|
|
1348
2228
|
reuc = git_vector_get(&index->reuc, position);
|
1349
2229
|
error = git_vector_remove(&index->reuc, position);
|
@@ -1351,27 +2231,27 @@ int git_index_reuc_remove(git_index *index, size_t position)
|
|
1351
2231
|
if (!error)
|
1352
2232
|
index_entry_reuc_free(reuc);
|
1353
2233
|
|
2234
|
+
index->dirty = 1;
|
1354
2235
|
return error;
|
1355
2236
|
}
|
1356
2237
|
|
1357
2238
|
void git_index_reuc_clear(git_index *index)
|
1358
2239
|
{
|
1359
2240
|
size_t i;
|
1360
|
-
git_index_reuc_entry *reuc;
|
1361
2241
|
|
1362
2242
|
assert(index);
|
1363
2243
|
|
1364
|
-
|
1365
|
-
|
1366
|
-
git__free(reuc);
|
1367
|
-
}
|
2244
|
+
for (i = 0; i < index->reuc.length; ++i)
|
2245
|
+
index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL));
|
1368
2246
|
|
1369
2247
|
git_vector_clear(&index->reuc);
|
2248
|
+
|
2249
|
+
index->dirty = 1;
|
1370
2250
|
}
|
1371
2251
|
|
1372
2252
|
static int index_error_invalid(const char *message)
|
1373
2253
|
{
|
1374
|
-
|
2254
|
+
git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message);
|
1375
2255
|
return -1;
|
1376
2256
|
}
|
1377
2257
|
|
@@ -1389,34 +2269,34 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
|
|
1389
2269
|
while (size) {
|
1390
2270
|
git_index_reuc_entry *lost;
|
1391
2271
|
|
1392
|
-
len =
|
2272
|
+
len = p_strnlen(buffer, size) + 1;
|
1393
2273
|
if (size <= len)
|
1394
2274
|
return index_error_invalid("reading reuc entries");
|
1395
2275
|
|
1396
|
-
lost =
|
1397
|
-
|
1398
|
-
|
1399
|
-
/* read NUL-terminated pathname for entry */
|
1400
|
-
lost->path = git__strdup(buffer);
|
1401
|
-
GITERR_CHECK_ALLOC(lost->path);
|
2276
|
+
lost = reuc_entry_alloc(buffer);
|
2277
|
+
GIT_ERROR_CHECK_ALLOC(lost);
|
1402
2278
|
|
1403
2279
|
size -= len;
|
1404
2280
|
buffer += len;
|
1405
2281
|
|
1406
2282
|
/* read 3 ASCII octal numbers for stage entries */
|
1407
2283
|
for (i = 0; i < 3; i++) {
|
1408
|
-
|
2284
|
+
int64_t tmp;
|
1409
2285
|
|
1410
|
-
if (
|
2286
|
+
if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 ||
|
1411
2287
|
!endptr || endptr == buffer || *endptr ||
|
1412
|
-
|
2288
|
+
tmp < 0 || tmp > UINT32_MAX) {
|
2289
|
+
index_entry_reuc_free(lost);
|
1413
2290
|
return index_error_invalid("reading reuc entry stage");
|
2291
|
+
}
|
1414
2292
|
|
1415
|
-
lost->mode[i] = tmp;
|
2293
|
+
lost->mode[i] = (uint32_t)tmp;
|
1416
2294
|
|
1417
2295
|
len = (endptr + 1) - buffer;
|
1418
|
-
if (size <= len)
|
2296
|
+
if (size <= len) {
|
2297
|
+
index_entry_reuc_free(lost);
|
1419
2298
|
return index_error_invalid("reading reuc entry stage");
|
2299
|
+
}
|
1420
2300
|
|
1421
2301
|
size -= len;
|
1422
2302
|
buffer += len;
|
@@ -1426,8 +2306,10 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
|
|
1426
2306
|
for (i = 0; i < 3; i++) {
|
1427
2307
|
if (!lost->mode[i])
|
1428
2308
|
continue;
|
1429
|
-
if (size < 20)
|
2309
|
+
if (size < 20) {
|
2310
|
+
index_entry_reuc_free(lost);
|
1430
2311
|
return index_error_invalid("reading reuc entry oid");
|
2312
|
+
}
|
1431
2313
|
|
1432
2314
|
git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer);
|
1433
2315
|
size -= 20;
|
@@ -1440,7 +2322,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
|
|
1440
2322
|
}
|
1441
2323
|
|
1442
2324
|
/* entries are guaranteed to be sorted on-disk */
|
1443
|
-
index->reuc
|
2325
|
+
git_vector_set_sorted(&index->reuc, true);
|
1444
2326
|
|
1445
2327
|
return 0;
|
1446
2328
|
}
|
@@ -1456,15 +2338,16 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
|
|
1456
2338
|
return -1;
|
1457
2339
|
|
1458
2340
|
#define read_conflict_name(ptr) \
|
1459
|
-
len =
|
1460
|
-
if (size < len) \
|
1461
|
-
|
1462
|
-
|
2341
|
+
len = p_strnlen(buffer, size) + 1; \
|
2342
|
+
if (size < len) { \
|
2343
|
+
index_error_invalid("reading conflict name entries"); \
|
2344
|
+
goto out_err; \
|
2345
|
+
} \
|
1463
2346
|
if (len == 1) \
|
1464
2347
|
ptr = NULL; \
|
1465
2348
|
else { \
|
1466
2349
|
ptr = git__malloc(len); \
|
1467
|
-
|
2350
|
+
GIT_ERROR_CHECK_ALLOC(ptr); \
|
1468
2351
|
memcpy(ptr, buffer, len); \
|
1469
2352
|
} \
|
1470
2353
|
\
|
@@ -1473,84 +2356,157 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
|
|
1473
2356
|
|
1474
2357
|
while (size) {
|
1475
2358
|
git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
|
1476
|
-
|
2359
|
+
GIT_ERROR_CHECK_ALLOC(conflict_name);
|
1477
2360
|
|
1478
2361
|
read_conflict_name(conflict_name->ancestor);
|
1479
2362
|
read_conflict_name(conflict_name->ours);
|
1480
2363
|
read_conflict_name(conflict_name->theirs);
|
1481
2364
|
|
1482
2365
|
if (git_vector_insert(&index->names, conflict_name) < 0)
|
1483
|
-
|
2366
|
+
goto out_err;
|
2367
|
+
|
2368
|
+
continue;
|
2369
|
+
|
2370
|
+
out_err:
|
2371
|
+
git__free(conflict_name->ancestor);
|
2372
|
+
git__free(conflict_name->ours);
|
2373
|
+
git__free(conflict_name->theirs);
|
2374
|
+
git__free(conflict_name);
|
2375
|
+
return -1;
|
1484
2376
|
}
|
1485
2377
|
|
1486
2378
|
#undef read_conflict_name
|
1487
2379
|
|
1488
2380
|
/* entries are guaranteed to be sorted on-disk */
|
1489
|
-
index->names
|
2381
|
+
git_vector_set_sorted(&index->names, true);
|
1490
2382
|
|
1491
2383
|
return 0;
|
1492
2384
|
}
|
1493
2385
|
|
1494
|
-
static size_t
|
2386
|
+
static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags)
|
2387
|
+
{
|
2388
|
+
if (varint_len) {
|
2389
|
+
if (flags & GIT_INDEX_ENTRY_EXTENDED)
|
2390
|
+
return offsetof(struct entry_long, path) + path_len + 1 + varint_len;
|
2391
|
+
else
|
2392
|
+
return offsetof(struct entry_short, path) + path_len + 1 + varint_len;
|
2393
|
+
} else {
|
2394
|
+
#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
|
2395
|
+
if (flags & GIT_INDEX_ENTRY_EXTENDED)
|
2396
|
+
return entry_size(struct entry_long, path_len);
|
2397
|
+
else
|
2398
|
+
return entry_size(struct entry_short, path_len);
|
2399
|
+
#undef entry_size
|
2400
|
+
}
|
2401
|
+
}
|
2402
|
+
|
2403
|
+
static int read_entry(
|
2404
|
+
git_index_entry **out,
|
2405
|
+
size_t *out_size,
|
2406
|
+
git_index *index,
|
2407
|
+
const void *buffer,
|
2408
|
+
size_t buffer_size,
|
2409
|
+
const char *last)
|
1495
2410
|
{
|
1496
2411
|
size_t path_length, entry_size;
|
1497
|
-
uint16_t flags_raw;
|
1498
2412
|
const char *path_ptr;
|
1499
|
-
|
2413
|
+
struct entry_short source;
|
2414
|
+
git_index_entry entry = {{0}};
|
2415
|
+
bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP;
|
2416
|
+
char *tmp_path = NULL;
|
1500
2417
|
|
1501
2418
|
if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
|
1502
|
-
return
|
2419
|
+
return -1;
|
1503
2420
|
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
2421
|
+
/* buffer is not guaranteed to be aligned */
|
2422
|
+
memcpy(&source, buffer, sizeof(struct entry_short));
|
2423
|
+
|
2424
|
+
entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds);
|
2425
|
+
entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds);
|
2426
|
+
entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds);
|
2427
|
+
entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds);
|
2428
|
+
entry.dev = ntohl(source.dev);
|
2429
|
+
entry.ino = ntohl(source.ino);
|
2430
|
+
entry.mode = ntohl(source.mode);
|
2431
|
+
entry.uid = ntohl(source.uid);
|
2432
|
+
entry.gid = ntohl(source.gid);
|
2433
|
+
entry.file_size = ntohl(source.file_size);
|
2434
|
+
git_oid_cpy(&entry.id, &source.oid);
|
2435
|
+
entry.flags = ntohs(source.flags);
|
2436
|
+
|
2437
|
+
if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) {
|
2438
|
+
uint16_t flags_raw;
|
2439
|
+
size_t flags_offset;
|
2440
|
+
|
2441
|
+
flags_offset = offsetof(struct entry_long, flags_extended);
|
2442
|
+
memcpy(&flags_raw, (const char *) buffer + flags_offset,
|
2443
|
+
sizeof(flags_raw));
|
2444
|
+
flags_raw = ntohs(flags_raw);
|
2445
|
+
|
2446
|
+
memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw));
|
2447
|
+
path_ptr = (const char *) buffer + offsetof(struct entry_long, path);
|
1525
2448
|
} else
|
1526
|
-
path_ptr =
|
2449
|
+
path_ptr = (const char *) buffer + offsetof(struct entry_short, path);
|
1527
2450
|
|
1528
|
-
|
2451
|
+
if (!compressed) {
|
2452
|
+
path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK;
|
1529
2453
|
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
2454
|
+
/* if this is a very long string, we must find its
|
2455
|
+
* real length without overflowing */
|
2456
|
+
if (path_length == 0xFFF) {
|
2457
|
+
const char *path_end;
|
1534
2458
|
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
2459
|
+
path_end = memchr(path_ptr, '\0', buffer_size);
|
2460
|
+
if (path_end == NULL)
|
2461
|
+
return -1;
|
2462
|
+
|
2463
|
+
path_length = path_end - path_ptr;
|
2464
|
+
}
|
2465
|
+
|
2466
|
+
entry_size = index_entry_size(path_length, 0, entry.flags);
|
2467
|
+
entry.path = (char *)path_ptr;
|
2468
|
+
} else {
|
2469
|
+
size_t varint_len, last_len, prefix_len, suffix_len, path_len;
|
2470
|
+
uintmax_t strip_len;
|
2471
|
+
|
2472
|
+
strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len);
|
2473
|
+
last_len = strlen(last);
|
2474
|
+
|
2475
|
+
if (varint_len == 0 || last_len < strip_len)
|
2476
|
+
return index_error_invalid("incorrect prefix length");
|
2477
|
+
|
2478
|
+
prefix_len = last_len - (size_t)strip_len;
|
2479
|
+
suffix_len = strlen(path_ptr + varint_len);
|
2480
|
+
|
2481
|
+
GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
|
2482
|
+
GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
|
2483
|
+
|
2484
|
+
if (path_len > GIT_PATH_MAX)
|
2485
|
+
return index_error_invalid("unreasonable path length");
|
1538
2486
|
|
1539
|
-
|
2487
|
+
tmp_path = git__malloc(path_len);
|
2488
|
+
GIT_ERROR_CHECK_ALLOC(tmp_path);
|
2489
|
+
|
2490
|
+
memcpy(tmp_path, last, prefix_len);
|
2491
|
+
memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
|
2492
|
+
entry_size = index_entry_size(suffix_len, varint_len, entry.flags);
|
2493
|
+
entry.path = tmp_path;
|
1540
2494
|
}
|
1541
2495
|
|
1542
|
-
if (
|
1543
|
-
|
1544
|
-
else
|
1545
|
-
entry_size = short_entry_size(path_length);
|
2496
|
+
if (entry_size == 0)
|
2497
|
+
return -1;
|
1546
2498
|
|
1547
2499
|
if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
|
1548
|
-
return
|
2500
|
+
return -1;
|
1549
2501
|
|
1550
|
-
|
1551
|
-
|
2502
|
+
if (index_entry_dup(out, index, &entry) < 0) {
|
2503
|
+
git__free(tmp_path);
|
2504
|
+
return -1;
|
2505
|
+
}
|
1552
2506
|
|
1553
|
-
|
2507
|
+
git__free(tmp_path);
|
2508
|
+
*out_size = entry_size;
|
2509
|
+
return 0;
|
1554
2510
|
}
|
1555
2511
|
|
1556
2512
|
static int read_header(struct index_header *dest, const void *buffer)
|
@@ -1562,64 +2518,72 @@ static int read_header(struct index_header *dest, const void *buffer)
|
|
1562
2518
|
return index_error_invalid("incorrect header signature");
|
1563
2519
|
|
1564
2520
|
dest->version = ntohl(source->version);
|
1565
|
-
if (dest->version
|
1566
|
-
dest->version
|
2521
|
+
if (dest->version < INDEX_VERSION_NUMBER_LB ||
|
2522
|
+
dest->version > INDEX_VERSION_NUMBER_UB)
|
1567
2523
|
return index_error_invalid("incorrect header version");
|
1568
2524
|
|
1569
2525
|
dest->entry_count = ntohl(source->entry_count);
|
1570
2526
|
return 0;
|
1571
2527
|
}
|
1572
2528
|
|
1573
|
-
static
|
2529
|
+
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size)
|
1574
2530
|
{
|
1575
|
-
const struct index_extension *source;
|
1576
2531
|
struct index_extension dest;
|
1577
2532
|
size_t total_size;
|
1578
2533
|
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
dest.extension_size = ntohl(source->extension_size);
|
2534
|
+
/* buffer is not guaranteed to be aligned */
|
2535
|
+
memcpy(&dest, buffer, sizeof(struct index_extension));
|
2536
|
+
dest.extension_size = ntohl(dest.extension_size);
|
1583
2537
|
|
1584
2538
|
total_size = dest.extension_size + sizeof(struct index_extension);
|
1585
2539
|
|
1586
|
-
if (
|
1587
|
-
buffer_size
|
1588
|
-
|
2540
|
+
if (dest.extension_size > total_size ||
|
2541
|
+
buffer_size < total_size ||
|
2542
|
+
buffer_size - total_size < INDEX_FOOTER_SIZE) {
|
2543
|
+
index_error_invalid("extension is truncated");
|
2544
|
+
return -1;
|
2545
|
+
}
|
1589
2546
|
|
1590
2547
|
/* optional extension */
|
1591
2548
|
if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
|
1592
2549
|
/* tree cache */
|
1593
2550
|
if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
|
1594
|
-
if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < 0)
|
1595
|
-
return
|
2551
|
+
if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0)
|
2552
|
+
return -1;
|
1596
2553
|
} else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
|
1597
2554
|
if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
|
1598
|
-
return
|
2555
|
+
return -1;
|
1599
2556
|
} else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
|
1600
2557
|
if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
|
1601
|
-
return
|
2558
|
+
return -1;
|
1602
2559
|
}
|
1603
2560
|
/* else, unsupported extension. We cannot parse this, but we can skip
|
1604
2561
|
* it by returning `total_size */
|
1605
2562
|
} else {
|
1606
2563
|
/* we cannot handle non-ignorable extensions;
|
1607
2564
|
* in fact they aren't even defined in the standard */
|
1608
|
-
|
2565
|
+
git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature);
|
2566
|
+
return -1;
|
1609
2567
|
}
|
1610
2568
|
|
1611
|
-
|
2569
|
+
*read_len = total_size;
|
2570
|
+
|
2571
|
+
return 0;
|
1612
2572
|
}
|
1613
2573
|
|
1614
2574
|
static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
|
1615
2575
|
{
|
2576
|
+
int error = 0;
|
1616
2577
|
unsigned int i;
|
1617
2578
|
struct index_header header = { 0 };
|
1618
2579
|
git_oid checksum_calculated, checksum_expected;
|
2580
|
+
const char *last = NULL;
|
2581
|
+
const char *empty = "";
|
1619
2582
|
|
1620
2583
|
#define seek_forward(_increase) { \
|
1621
|
-
if (_increase >= buffer_size) \
|
1622
|
-
|
2584
|
+
if (_increase >= buffer_size) { \
|
2585
|
+
error = index_error_invalid("ran out of data while parsing"); \
|
2586
|
+
goto done; } \
|
1623
2587
|
buffer += _increase; \
|
1624
2588
|
buffer_size -= _increase;\
|
1625
2589
|
}
|
@@ -1632,65 +2596,95 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
|
|
1632
2596
|
git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE);
|
1633
2597
|
|
1634
2598
|
/* Parse header */
|
1635
|
-
if (read_header(&header, buffer) < 0)
|
1636
|
-
return
|
2599
|
+
if ((error = read_header(&header, buffer)) < 0)
|
2600
|
+
return error;
|
2601
|
+
|
2602
|
+
index->version = header.version;
|
2603
|
+
if (index->version >= INDEX_VERSION_NUMBER_COMP)
|
2604
|
+
last = empty;
|
1637
2605
|
|
1638
2606
|
seek_forward(INDEX_HEADER_SIZE);
|
1639
2607
|
|
1640
|
-
|
2608
|
+
assert(!index->entries.length);
|
2609
|
+
|
2610
|
+
if (index->ignore_case)
|
2611
|
+
git_idxmap_icase_resize((git_idxmap_icase *) index->entries_map, header.entry_count);
|
2612
|
+
else
|
2613
|
+
git_idxmap_resize(index->entries_map, header.entry_count);
|
1641
2614
|
|
1642
2615
|
/* Parse all the entries */
|
1643
2616
|
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
|
2617
|
+
git_index_entry *entry = NULL;
|
1644
2618
|
size_t entry_size;
|
1645
|
-
git_index_entry *entry;
|
1646
2619
|
|
1647
|
-
|
1648
|
-
|
2620
|
+
if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) {
|
2621
|
+
error = index_error_invalid("invalid entry");
|
2622
|
+
goto done;
|
2623
|
+
}
|
2624
|
+
|
2625
|
+
if ((error = git_vector_insert(&index->entries, entry)) < 0) {
|
2626
|
+
index_entry_free(entry);
|
2627
|
+
goto done;
|
2628
|
+
}
|
1649
2629
|
|
1650
|
-
|
2630
|
+
INSERT_IN_MAP(index, entry, &error);
|
1651
2631
|
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
2632
|
+
if (error < 0) {
|
2633
|
+
index_entry_free(entry);
|
2634
|
+
goto done;
|
2635
|
+
}
|
2636
|
+
error = 0;
|
1655
2637
|
|
1656
|
-
if (
|
1657
|
-
|
2638
|
+
if (index->version >= INDEX_VERSION_NUMBER_COMP)
|
2639
|
+
last = entry->path;
|
1658
2640
|
|
1659
2641
|
seek_forward(entry_size);
|
1660
2642
|
}
|
1661
2643
|
|
1662
|
-
if (i != header.entry_count)
|
1663
|
-
|
2644
|
+
if (i != header.entry_count) {
|
2645
|
+
error = index_error_invalid("header entries changed while parsing");
|
2646
|
+
goto done;
|
2647
|
+
}
|
1664
2648
|
|
1665
2649
|
/* There's still space for some extensions! */
|
1666
2650
|
while (buffer_size > INDEX_FOOTER_SIZE) {
|
1667
2651
|
size_t extension_size;
|
1668
2652
|
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1672
|
-
if (extension_size == 0)
|
1673
|
-
return index_error_invalid("extension is truncated");
|
2653
|
+
if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) {
|
2654
|
+
goto done;
|
2655
|
+
}
|
1674
2656
|
|
1675
2657
|
seek_forward(extension_size);
|
1676
2658
|
}
|
1677
2659
|
|
1678
|
-
if (buffer_size != INDEX_FOOTER_SIZE)
|
1679
|
-
|
2660
|
+
if (buffer_size != INDEX_FOOTER_SIZE) {
|
2661
|
+
error = index_error_invalid(
|
2662
|
+
"buffer size does not match index footer size");
|
2663
|
+
goto done;
|
2664
|
+
}
|
1680
2665
|
|
1681
2666
|
/* 160-bit SHA-1 over the content of the index file before this checksum. */
|
1682
2667
|
git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
|
1683
2668
|
|
1684
|
-
if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0)
|
1685
|
-
|
2669
|
+
if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) {
|
2670
|
+
error = index_error_invalid(
|
2671
|
+
"calculated checksum does not match expected");
|
2672
|
+
goto done;
|
2673
|
+
}
|
2674
|
+
|
2675
|
+
git_oid_cpy(&index->checksum, &checksum_calculated);
|
1686
2676
|
|
1687
2677
|
#undef seek_forward
|
1688
2678
|
|
1689
|
-
/* Entries are stored case-sensitively on disk
|
1690
|
-
|
2679
|
+
/* Entries are stored case-sensitively on disk, so re-sort now if
|
2680
|
+
* in-memory index is supposed to be case-insensitive
|
2681
|
+
*/
|
2682
|
+
git_vector_set_sorted(&index->entries, !index->ignore_case);
|
1691
2683
|
git_vector_sort(&index->entries);
|
1692
2684
|
|
1693
|
-
|
2685
|
+
index->dirty = 0;
|
2686
|
+
done:
|
2687
|
+
return error;
|
1694
2688
|
}
|
1695
2689
|
|
1696
2690
|
static bool is_index_extended(git_index *index)
|
@@ -1701,36 +2695,48 @@ static bool is_index_extended(git_index *index)
|
|
1701
2695
|
extended = 0;
|
1702
2696
|
|
1703
2697
|
git_vector_foreach(&index->entries, i, entry) {
|
1704
|
-
entry->flags &= ~
|
1705
|
-
if (entry->flags_extended &
|
2698
|
+
entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED;
|
2699
|
+
if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) {
|
1706
2700
|
extended++;
|
1707
|
-
entry->flags |=
|
2701
|
+
entry->flags |= GIT_INDEX_ENTRY_EXTENDED;
|
1708
2702
|
}
|
1709
2703
|
}
|
1710
2704
|
|
1711
2705
|
return (extended > 0);
|
1712
2706
|
}
|
1713
2707
|
|
1714
|
-
static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
|
2708
|
+
static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last)
|
1715
2709
|
{
|
1716
2710
|
void *mem = NULL;
|
1717
|
-
struct entry_short
|
2711
|
+
struct entry_short ondisk;
|
1718
2712
|
size_t path_len, disk_size;
|
2713
|
+
int varint_len = 0;
|
1719
2714
|
char *path;
|
2715
|
+
const char *path_start = entry->path;
|
2716
|
+
size_t same_len = 0;
|
1720
2717
|
|
1721
|
-
path_len =
|
2718
|
+
path_len = ((struct entry_internal *)entry)->pathlen;
|
1722
2719
|
|
1723
|
-
if (
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
2720
|
+
if (last) {
|
2721
|
+
const char *last_c = last;
|
2722
|
+
|
2723
|
+
while (*path_start == *last_c) {
|
2724
|
+
if (!*path_start || !*last_c)
|
2725
|
+
break;
|
2726
|
+
++path_start;
|
2727
|
+
++last_c;
|
2728
|
+
++same_len;
|
2729
|
+
}
|
2730
|
+
path_len -= same_len;
|
2731
|
+
varint_len = git_encode_varint(NULL, 0, same_len);
|
2732
|
+
}
|
2733
|
+
|
2734
|
+
disk_size = index_entry_size(path_len, varint_len, entry->flags);
|
1727
2735
|
|
1728
2736
|
if (git_filebuf_reserve(file, &mem, disk_size) < 0)
|
1729
2737
|
return -1;
|
1730
2738
|
|
1731
|
-
|
1732
|
-
|
1733
|
-
memset(ondisk, 0x0, disk_size);
|
2739
|
+
memset(mem, 0x0, disk_size);
|
1734
2740
|
|
1735
2741
|
/**
|
1736
2742
|
* Yes, we have to truncate.
|
@@ -1742,31 +2748,57 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
|
|
1742
2748
|
*
|
1743
2749
|
* In 2038 I will be either too dead or too rich to care about this
|
1744
2750
|
*/
|
1745
|
-
ondisk
|
1746
|
-
ondisk
|
1747
|
-
ondisk
|
1748
|
-
ondisk
|
1749
|
-
ondisk
|
1750
|
-
ondisk
|
1751
|
-
ondisk
|
1752
|
-
ondisk
|
1753
|
-
ondisk
|
1754
|
-
ondisk
|
1755
|
-
|
1756
|
-
git_oid_cpy(&ondisk
|
1757
|
-
|
1758
|
-
ondisk
|
1759
|
-
|
1760
|
-
if (entry->flags &
|
1761
|
-
struct entry_long
|
1762
|
-
ondisk_ext
|
1763
|
-
ondisk_ext
|
1764
|
-
|
2751
|
+
ondisk.ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
|
2752
|
+
ondisk.mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
|
2753
|
+
ondisk.ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
|
2754
|
+
ondisk.mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
|
2755
|
+
ondisk.dev = htonl(entry->dev);
|
2756
|
+
ondisk.ino = htonl(entry->ino);
|
2757
|
+
ondisk.mode = htonl(entry->mode);
|
2758
|
+
ondisk.uid = htonl(entry->uid);
|
2759
|
+
ondisk.gid = htonl(entry->gid);
|
2760
|
+
ondisk.file_size = htonl((uint32_t)entry->file_size);
|
2761
|
+
|
2762
|
+
git_oid_cpy(&ondisk.oid, &entry->id);
|
2763
|
+
|
2764
|
+
ondisk.flags = htons(entry->flags);
|
2765
|
+
|
2766
|
+
if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) {
|
2767
|
+
struct entry_long ondisk_ext;
|
2768
|
+
memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short));
|
2769
|
+
ondisk_ext.flags_extended = htons(entry->flags_extended &
|
2770
|
+
GIT_INDEX_ENTRY_EXTENDED_FLAGS);
|
2771
|
+
memcpy(mem, &ondisk_ext, offsetof(struct entry_long, path));
|
2772
|
+
path = ((struct entry_long*)mem)->path;
|
2773
|
+
disk_size -= offsetof(struct entry_long, path);
|
2774
|
+
} else {
|
2775
|
+
memcpy(mem, &ondisk, offsetof(struct entry_short, path));
|
2776
|
+
path = ((struct entry_short*)mem)->path;
|
2777
|
+
disk_size -= offsetof(struct entry_short, path);
|
1765
2778
|
}
|
1766
|
-
else
|
1767
|
-
path = ondisk->path;
|
1768
2779
|
|
1769
|
-
|
2780
|
+
if (last) {
|
2781
|
+
varint_len = git_encode_varint((unsigned char *) path,
|
2782
|
+
disk_size, same_len);
|
2783
|
+
assert(varint_len > 0);
|
2784
|
+
path += varint_len;
|
2785
|
+
disk_size -= varint_len;
|
2786
|
+
|
2787
|
+
/*
|
2788
|
+
* If using path compression, we are not allowed
|
2789
|
+
* to have additional trailing NULs.
|
2790
|
+
*/
|
2791
|
+
assert(disk_size == path_len + 1);
|
2792
|
+
} else {
|
2793
|
+
/*
|
2794
|
+
* If no path compression is used, we do have
|
2795
|
+
* NULs as padding. As such, simply assert that
|
2796
|
+
* we have enough space left to write the path.
|
2797
|
+
*/
|
2798
|
+
assert(disk_size > path_len);
|
2799
|
+
}
|
2800
|
+
|
2801
|
+
memcpy(path, path_start, path_len + 1);
|
1770
2802
|
|
1771
2803
|
return 0;
|
1772
2804
|
}
|
@@ -1775,21 +2807,29 @@ static int write_entries(git_index *index, git_filebuf *file)
|
|
1775
2807
|
{
|
1776
2808
|
int error = 0;
|
1777
2809
|
size_t i;
|
1778
|
-
git_vector case_sorted;
|
2810
|
+
git_vector case_sorted, *entries;
|
1779
2811
|
git_index_entry *entry;
|
1780
|
-
|
2812
|
+
const char *last = NULL;
|
1781
2813
|
|
1782
2814
|
/* If index->entries is sorted case-insensitively, then we need
|
1783
2815
|
* to re-sort it case-sensitively before writing */
|
1784
2816
|
if (index->ignore_case) {
|
1785
|
-
git_vector_dup(&case_sorted, &index->entries,
|
2817
|
+
git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp);
|
1786
2818
|
git_vector_sort(&case_sorted);
|
1787
|
-
|
2819
|
+
entries = &case_sorted;
|
2820
|
+
} else {
|
2821
|
+
entries = &index->entries;
|
1788
2822
|
}
|
1789
2823
|
|
1790
|
-
|
1791
|
-
|
2824
|
+
if (index->version >= INDEX_VERSION_NUMBER_COMP)
|
2825
|
+
last = "";
|
2826
|
+
|
2827
|
+
git_vector_foreach(entries, i, entry) {
|
2828
|
+
if ((error = write_disk_entry(file, entry, last)) < 0)
|
1792
2829
|
break;
|
2830
|
+
if (index->version >= INDEX_VERSION_NUMBER_COMP)
|
2831
|
+
last = entry->path;
|
2832
|
+
}
|
1793
2833
|
|
1794
2834
|
if (index->ignore_case)
|
1795
2835
|
git_vector_free(&case_sorted);
|
@@ -1800,16 +2840,13 @@ static int write_entries(git_index *index, git_filebuf *file)
|
|
1800
2840
|
static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data)
|
1801
2841
|
{
|
1802
2842
|
struct index_extension ondisk;
|
1803
|
-
int error = 0;
|
1804
2843
|
|
1805
2844
|
memset(&ondisk, 0x0, sizeof(struct index_extension));
|
1806
2845
|
memcpy(&ondisk, header, 4);
|
1807
2846
|
ondisk.extension_size = htonl(header->extension_size);
|
1808
2847
|
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
return error;
|
2848
|
+
git_filebuf_write(file, &ondisk, sizeof(struct index_extension));
|
2849
|
+
return git_filebuf_write(file, data->ptr, data->size);
|
1813
2850
|
}
|
1814
2851
|
|
1815
2852
|
static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name)
|
@@ -1861,7 +2898,7 @@ static int write_name_extension(git_index *index, git_filebuf *file)
|
|
1861
2898
|
|
1862
2899
|
error = write_extension(file, &extension, &name_buf);
|
1863
2900
|
|
1864
|
-
|
2901
|
+
git_buf_dispose(&name_buf);
|
1865
2902
|
|
1866
2903
|
done:
|
1867
2904
|
return error;
|
@@ -1909,24 +2946,62 @@ static int write_reuc_extension(git_index *index, git_filebuf *file)
|
|
1909
2946
|
|
1910
2947
|
error = write_extension(file, &extension, &reuc_buf);
|
1911
2948
|
|
1912
|
-
|
2949
|
+
git_buf_dispose(&reuc_buf);
|
1913
2950
|
|
1914
2951
|
done:
|
1915
2952
|
return error;
|
1916
2953
|
}
|
1917
2954
|
|
1918
|
-
static int
|
2955
|
+
static int write_tree_extension(git_index *index, git_filebuf *file)
|
2956
|
+
{
|
2957
|
+
struct index_extension extension;
|
2958
|
+
git_buf buf = GIT_BUF_INIT;
|
2959
|
+
int error;
|
2960
|
+
|
2961
|
+
if (index->tree == NULL)
|
2962
|
+
return 0;
|
2963
|
+
|
2964
|
+
if ((error = git_tree_cache_write(&buf, index->tree)) < 0)
|
2965
|
+
return error;
|
2966
|
+
|
2967
|
+
memset(&extension, 0x0, sizeof(struct index_extension));
|
2968
|
+
memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4);
|
2969
|
+
extension.extension_size = (uint32_t)buf.size;
|
2970
|
+
|
2971
|
+
error = write_extension(file, &extension, &buf);
|
2972
|
+
|
2973
|
+
git_buf_dispose(&buf);
|
2974
|
+
|
2975
|
+
return error;
|
2976
|
+
}
|
2977
|
+
|
2978
|
+
static void clear_uptodate(git_index *index)
|
2979
|
+
{
|
2980
|
+
git_index_entry *entry;
|
2981
|
+
size_t i;
|
2982
|
+
|
2983
|
+
git_vector_foreach(&index->entries, i, entry)
|
2984
|
+
entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE;
|
2985
|
+
}
|
2986
|
+
|
2987
|
+
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
|
1919
2988
|
{
|
1920
2989
|
git_oid hash_final;
|
1921
2990
|
struct index_header header;
|
1922
2991
|
bool is_extended;
|
2992
|
+
uint32_t index_version_number;
|
1923
2993
|
|
1924
2994
|
assert(index && file);
|
1925
2995
|
|
1926
|
-
|
2996
|
+
if (index->version <= INDEX_VERSION_NUMBER_EXT) {
|
2997
|
+
is_extended = is_index_extended(index);
|
2998
|
+
index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB;
|
2999
|
+
} else {
|
3000
|
+
index_version_number = index->version;
|
3001
|
+
}
|
1927
3002
|
|
1928
3003
|
header.signature = htonl(INDEX_HEADER_SIG);
|
1929
|
-
header.version = htonl(
|
3004
|
+
header.version = htonl(index_version_number);
|
1930
3005
|
header.entry_count = htonl((uint32_t)index->entries.length);
|
1931
3006
|
|
1932
3007
|
if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
|
@@ -1935,7 +3010,9 @@ static int write_index(git_index *index, git_filebuf *file)
|
|
1935
3010
|
if (write_entries(index, file) < 0)
|
1936
3011
|
return -1;
|
1937
3012
|
|
1938
|
-
/*
|
3013
|
+
/* write the tree cache extension */
|
3014
|
+
if (index->tree != NULL && write_tree_extension(index, file) < 0)
|
3015
|
+
return -1;
|
1939
3016
|
|
1940
3017
|
/* write the rename conflict extension */
|
1941
3018
|
if (index->names.length > 0 && write_name_extension(index, file) < 0)
|
@@ -1947,19 +3024,34 @@ static int write_index(git_index *index, git_filebuf *file)
|
|
1947
3024
|
|
1948
3025
|
/* get out the hash for all the contents we've appended to the file */
|
1949
3026
|
git_filebuf_hash(&hash_final, file);
|
3027
|
+
git_oid_cpy(checksum, &hash_final);
|
1950
3028
|
|
1951
3029
|
/* write it at the end of the file */
|
1952
|
-
|
3030
|
+
if (git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ) < 0)
|
3031
|
+
return -1;
|
3032
|
+
|
3033
|
+
/* file entries are no longer up to date */
|
3034
|
+
clear_uptodate(index);
|
3035
|
+
|
3036
|
+
return 0;
|
1953
3037
|
}
|
1954
3038
|
|
1955
3039
|
int git_index_entry_stage(const git_index_entry *entry)
|
1956
3040
|
{
|
1957
|
-
return
|
3041
|
+
return GIT_INDEX_ENTRY_STAGE(entry);
|
3042
|
+
}
|
3043
|
+
|
3044
|
+
int git_index_entry_is_conflict(const git_index_entry *entry)
|
3045
|
+
{
|
3046
|
+
return (GIT_INDEX_ENTRY_STAGE(entry) > 0);
|
1958
3047
|
}
|
1959
3048
|
|
1960
3049
|
typedef struct read_tree_data {
|
1961
3050
|
git_index *index;
|
1962
3051
|
git_vector *old_entries;
|
3052
|
+
git_vector *new_entries;
|
3053
|
+
git_vector_cmp entry_cmp;
|
3054
|
+
git_tree_cache *tree;
|
1963
3055
|
} read_tree_data;
|
1964
3056
|
|
1965
3057
|
static int read_tree_cb(
|
@@ -1968,6 +3060,7 @@ static int read_tree_cb(
|
|
1968
3060
|
read_tree_data *data = payload;
|
1969
3061
|
git_index_entry *entry = NULL, *old_entry;
|
1970
3062
|
git_buf path = GIT_BUF_INIT;
|
3063
|
+
size_t pos;
|
1971
3064
|
|
1972
3065
|
if (git_tree_entry__is_tree(tentry))
|
1973
3066
|
return 0;
|
@@ -1975,40 +3068,28 @@ static int read_tree_cb(
|
|
1975
3068
|
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
|
1976
3069
|
return -1;
|
1977
3070
|
|
1978
|
-
|
1979
|
-
|
3071
|
+
if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0)
|
3072
|
+
return -1;
|
1980
3073
|
|
1981
3074
|
entry->mode = tentry->attr;
|
1982
|
-
entry->
|
3075
|
+
git_oid_cpy(&entry->id, git_tree_entry_id(tentry));
|
1983
3076
|
|
1984
3077
|
/* look for corresponding old entry and copy data to new entry */
|
1985
|
-
if (data->old_entries
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
(old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
|
1995
|
-
entry->mode == old_entry->mode &&
|
1996
|
-
git_oid_equal(&entry->oid, &old_entry->oid))
|
1997
|
-
{
|
1998
|
-
memcpy(entry, old_entry, sizeof(*entry));
|
1999
|
-
entry->flags_extended = 0;
|
2000
|
-
}
|
3078
|
+
if (data->old_entries != NULL &&
|
3079
|
+
!index_find_in_entries(
|
3080
|
+
&pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) &&
|
3081
|
+
(old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
|
3082
|
+
entry->mode == old_entry->mode &&
|
3083
|
+
git_oid_equal(&entry->id, &old_entry->id))
|
3084
|
+
{
|
3085
|
+
index_entry_cpy(entry, old_entry);
|
3086
|
+
entry->flags_extended = 0;
|
2001
3087
|
}
|
2002
3088
|
|
2003
|
-
|
2004
|
-
|
2005
|
-
else
|
2006
|
-
entry->flags = GIT_IDXENTRY_NAMEMASK;
|
2007
|
-
|
2008
|
-
entry->path = git_buf_detach(&path);
|
2009
|
-
git_buf_free(&path);
|
3089
|
+
index_entry_adjust_namemask(entry, path.size);
|
3090
|
+
git_buf_dispose(&path);
|
2010
3091
|
|
2011
|
-
if (git_vector_insert(
|
3092
|
+
if (git_vector_insert(data->new_entries, entry) < 0) {
|
2012
3093
|
index_entry_free(entry);
|
2013
3094
|
return -1;
|
2014
3095
|
}
|
@@ -2020,25 +3101,225 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
|
|
2020
3101
|
{
|
2021
3102
|
int error = 0;
|
2022
3103
|
git_vector entries = GIT_VECTOR_INIT;
|
3104
|
+
git_idxmap *entries_map;
|
2023
3105
|
read_tree_data data;
|
3106
|
+
size_t i;
|
3107
|
+
git_index_entry *e;
|
3108
|
+
|
3109
|
+
if (git_idxmap_alloc(&entries_map) < 0)
|
3110
|
+
return -1;
|
3111
|
+
|
3112
|
+
git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
|
3113
|
+
|
3114
|
+
data.index = index;
|
3115
|
+
data.old_entries = &index->entries;
|
3116
|
+
data.new_entries = &entries;
|
3117
|
+
data.entry_cmp = index->entries_search;
|
3118
|
+
|
3119
|
+
index->tree = NULL;
|
3120
|
+
git_pool_clear(&index->tree_pool);
|
2024
3121
|
|
2025
3122
|
git_vector_sort(&index->entries);
|
2026
3123
|
|
2027
|
-
|
2028
|
-
|
3124
|
+
if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
|
3125
|
+
goto cleanup;
|
3126
|
+
|
3127
|
+
if (index->ignore_case)
|
3128
|
+
git_idxmap_icase_resize((git_idxmap_icase *) entries_map, entries.length);
|
3129
|
+
else
|
3130
|
+
git_idxmap_resize(entries_map, entries.length);
|
2029
3131
|
|
2030
|
-
|
3132
|
+
git_vector_foreach(&entries, i, e) {
|
3133
|
+
INSERT_IN_MAP_EX(index, entries_map, e, &error);
|
2031
3134
|
|
2032
|
-
|
2033
|
-
|
3135
|
+
if (error < 0) {
|
3136
|
+
git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map");
|
3137
|
+
return error;
|
3138
|
+
}
|
3139
|
+
}
|
2034
3140
|
|
2035
|
-
error =
|
3141
|
+
error = 0;
|
2036
3142
|
|
2037
|
-
|
3143
|
+
git_vector_sort(&entries);
|
3144
|
+
|
3145
|
+
if ((error = git_index_clear(index)) < 0) {
|
3146
|
+
/* well, this isn't good */;
|
3147
|
+
} else {
|
3148
|
+
git_vector_swap(&entries, &index->entries);
|
3149
|
+
entries_map = git__swap(index->entries_map, entries_map);
|
3150
|
+
}
|
3151
|
+
|
3152
|
+
index->dirty = 1;
|
3153
|
+
|
3154
|
+
cleanup:
|
2038
3155
|
git_vector_free(&entries);
|
3156
|
+
git_idxmap_free(entries_map);
|
3157
|
+
if (error < 0)
|
3158
|
+
return error;
|
2039
3159
|
|
2040
|
-
|
3160
|
+
error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool);
|
3161
|
+
|
3162
|
+
return error;
|
3163
|
+
}
|
3164
|
+
|
3165
|
+
static int git_index_read_iterator(
|
3166
|
+
git_index *index,
|
3167
|
+
git_iterator *new_iterator,
|
3168
|
+
size_t new_length_hint)
|
3169
|
+
{
|
3170
|
+
git_vector new_entries = GIT_VECTOR_INIT,
|
3171
|
+
remove_entries = GIT_VECTOR_INIT;
|
3172
|
+
git_idxmap *new_entries_map = NULL;
|
3173
|
+
git_iterator *index_iterator = NULL;
|
3174
|
+
git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
|
3175
|
+
const git_index_entry *old_entry, *new_entry;
|
3176
|
+
git_index_entry *entry;
|
3177
|
+
size_t i;
|
3178
|
+
int error;
|
3179
|
+
|
3180
|
+
assert((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
|
3181
|
+
|
3182
|
+
if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
|
3183
|
+
(error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
|
3184
|
+
(error = git_idxmap_alloc(&new_entries_map)) < 0)
|
3185
|
+
goto done;
|
3186
|
+
|
3187
|
+
if (index->ignore_case && new_length_hint)
|
3188
|
+
git_idxmap_icase_resize((git_idxmap_icase *) new_entries_map, new_length_hint);
|
3189
|
+
else if (new_length_hint)
|
3190
|
+
git_idxmap_resize(new_entries_map, new_length_hint);
|
3191
|
+
|
3192
|
+
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
|
3193
|
+
GIT_ITERATOR_INCLUDE_CONFLICTS;
|
3194
|
+
|
3195
|
+
if ((error = git_iterator_for_index(&index_iterator,
|
3196
|
+
git_index_owner(index), index, &opts)) < 0 ||
|
3197
|
+
((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
|
3198
|
+
error != GIT_ITEROVER) ||
|
3199
|
+
((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
|
3200
|
+
error != GIT_ITEROVER))
|
3201
|
+
goto done;
|
3202
|
+
|
3203
|
+
while (true) {
|
3204
|
+
git_index_entry
|
3205
|
+
*dup_entry = NULL,
|
3206
|
+
*add_entry = NULL,
|
3207
|
+
*remove_entry = NULL;
|
3208
|
+
int diff;
|
3209
|
+
|
3210
|
+
error = 0;
|
3211
|
+
|
3212
|
+
if (old_entry && new_entry)
|
3213
|
+
diff = git_index_entry_cmp(old_entry, new_entry);
|
3214
|
+
else if (!old_entry && new_entry)
|
3215
|
+
diff = 1;
|
3216
|
+
else if (old_entry && !new_entry)
|
3217
|
+
diff = -1;
|
3218
|
+
else
|
3219
|
+
break;
|
3220
|
+
|
3221
|
+
if (diff < 0) {
|
3222
|
+
remove_entry = (git_index_entry *)old_entry;
|
3223
|
+
} else if (diff > 0) {
|
3224
|
+
dup_entry = (git_index_entry *)new_entry;
|
3225
|
+
} else {
|
3226
|
+
/* Path and stage are equal, if the OID is equal, keep it to
|
3227
|
+
* keep the stat cache data.
|
3228
|
+
*/
|
3229
|
+
if (git_oid_equal(&old_entry->id, &new_entry->id) &&
|
3230
|
+
old_entry->mode == new_entry->mode) {
|
3231
|
+
add_entry = (git_index_entry *)old_entry;
|
3232
|
+
} else {
|
3233
|
+
dup_entry = (git_index_entry *)new_entry;
|
3234
|
+
remove_entry = (git_index_entry *)old_entry;
|
3235
|
+
}
|
3236
|
+
}
|
3237
|
+
|
3238
|
+
if (dup_entry) {
|
3239
|
+
if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0)
|
3240
|
+
goto done;
|
3241
|
+
|
3242
|
+
index_entry_adjust_namemask(add_entry,
|
3243
|
+
((struct entry_internal *)add_entry)->pathlen);
|
3244
|
+
}
|
3245
|
+
|
3246
|
+
/* invalidate this path in the tree cache if this is new (to
|
3247
|
+
* invalidate the parent trees)
|
3248
|
+
*/
|
3249
|
+
if (dup_entry && !remove_entry && index->tree)
|
3250
|
+
git_tree_cache_invalidate_path(index->tree, dup_entry->path);
|
3251
|
+
|
3252
|
+
if (add_entry) {
|
3253
|
+
if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
|
3254
|
+
INSERT_IN_MAP_EX(index, new_entries_map, add_entry, &error);
|
3255
|
+
}
|
3256
|
+
|
3257
|
+
if (remove_entry && error >= 0)
|
3258
|
+
error = git_vector_insert(&remove_entries, remove_entry);
|
3259
|
+
|
3260
|
+
if (error < 0) {
|
3261
|
+
git_error_set(GIT_ERROR_INDEX, "failed to insert entry");
|
3262
|
+
goto done;
|
3263
|
+
}
|
3264
|
+
|
3265
|
+
if (diff <= 0) {
|
3266
|
+
if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 &&
|
3267
|
+
error != GIT_ITEROVER)
|
3268
|
+
goto done;
|
3269
|
+
}
|
3270
|
+
|
3271
|
+
if (diff >= 0) {
|
3272
|
+
if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 &&
|
3273
|
+
error != GIT_ITEROVER)
|
3274
|
+
goto done;
|
3275
|
+
}
|
3276
|
+
}
|
3277
|
+
|
3278
|
+
git_index_name_clear(index);
|
3279
|
+
git_index_reuc_clear(index);
|
3280
|
+
|
3281
|
+
git_vector_swap(&new_entries, &index->entries);
|
3282
|
+
new_entries_map = git__swap(index->entries_map, new_entries_map);
|
3283
|
+
|
3284
|
+
git_vector_foreach(&remove_entries, i, entry) {
|
3285
|
+
if (index->tree)
|
3286
|
+
git_tree_cache_invalidate_path(index->tree, entry->path);
|
3287
|
+
|
3288
|
+
index_entry_free(entry);
|
3289
|
+
}
|
3290
|
+
|
3291
|
+
clear_uptodate(index);
|
3292
|
+
|
3293
|
+
index->dirty = 1;
|
3294
|
+
error = 0;
|
3295
|
+
|
3296
|
+
done:
|
3297
|
+
git_idxmap_free(new_entries_map);
|
3298
|
+
git_vector_free(&new_entries);
|
3299
|
+
git_vector_free(&remove_entries);
|
3300
|
+
git_iterator_free(index_iterator);
|
3301
|
+
return error;
|
3302
|
+
}
|
3303
|
+
|
3304
|
+
int git_index_read_index(
|
3305
|
+
git_index *index,
|
3306
|
+
const git_index *new_index)
|
3307
|
+
{
|
3308
|
+
git_iterator *new_iterator = NULL;
|
3309
|
+
git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
|
3310
|
+
int error;
|
2041
3311
|
|
3312
|
+
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
|
3313
|
+
GIT_ITERATOR_INCLUDE_CONFLICTS;
|
3314
|
+
|
3315
|
+
if ((error = git_iterator_for_index(&new_iterator,
|
3316
|
+
git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 ||
|
3317
|
+
(error = git_index_read_iterator(index, new_iterator,
|
3318
|
+
new_index->entries.length)) < 0)
|
3319
|
+
goto done;
|
3320
|
+
|
3321
|
+
done:
|
3322
|
+
git_iterator_free(new_iterator);
|
2042
3323
|
return error;
|
2043
3324
|
}
|
2044
3325
|
|
@@ -2047,6 +3328,13 @@ git_repository *git_index_owner(const git_index *index)
|
|
2047
3328
|
return INDEX_OWNER(index);
|
2048
3329
|
}
|
2049
3330
|
|
3331
|
+
enum {
|
3332
|
+
INDEX_ACTION_NONE = 0,
|
3333
|
+
INDEX_ACTION_UPDATE = 1,
|
3334
|
+
INDEX_ACTION_REMOVE = 2,
|
3335
|
+
INDEX_ACTION_ADDALL = 3,
|
3336
|
+
};
|
3337
|
+
|
2050
3338
|
int git_index_add_all(
|
2051
3339
|
git_index *index,
|
2052
3340
|
const git_strarray *paths,
|
@@ -2057,30 +3345,16 @@ int git_index_add_all(
|
|
2057
3345
|
int error;
|
2058
3346
|
git_repository *repo;
|
2059
3347
|
git_iterator *wditer = NULL;
|
2060
|
-
|
2061
|
-
git_index_entry *entry;
|
2062
|
-
git_pathspec_context ps;
|
2063
|
-
const char *match;
|
2064
|
-
size_t existing;
|
3348
|
+
git_pathspec ps;
|
2065
3349
|
bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
|
2066
|
-
int ignorecase;
|
2067
|
-
git_oid blobid;
|
2068
3350
|
|
2069
3351
|
assert(index);
|
2070
3352
|
|
2071
|
-
if (INDEX_OWNER(index) == NULL)
|
2072
|
-
return create_index_error(-1,
|
2073
|
-
"Could not add paths to index. "
|
2074
|
-
"Index is not backed up by an existing repository.");
|
2075
|
-
|
2076
3353
|
repo = INDEX_OWNER(index);
|
2077
3354
|
if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
|
2078
3355
|
return error;
|
2079
3356
|
|
2080
|
-
if (
|
2081
|
-
return -1;
|
2082
|
-
|
2083
|
-
if ((error = git_pathspec_context_init(&ps, paths)) < 0)
|
3357
|
+
if ((error = git_pathspec__init(&ps, paths)) < 0)
|
2084
3358
|
return error;
|
2085
3359
|
|
2086
3360
|
/* optionally check that pathspec doesn't mention any ignored files */
|
@@ -2090,81 +3364,118 @@ int git_index_add_all(
|
|
2090
3364
|
repo, &ps.pathspec, no_fnmatch)) < 0)
|
2091
3365
|
goto cleanup;
|
2092
3366
|
|
2093
|
-
|
2094
|
-
&wditer, repo, 0, ps.prefix, ps.prefix)) < 0)
|
2095
|
-
goto cleanup;
|
3367
|
+
error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
|
2096
3368
|
|
2097
|
-
|
3369
|
+
if (error)
|
3370
|
+
git_error_set_after_callback(error);
|
2098
3371
|
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
continue;
|
3372
|
+
cleanup:
|
3373
|
+
git_iterator_free(wditer);
|
3374
|
+
git_pathspec__clear(&ps);
|
2103
3375
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
git_iterator_current_is_ignored(wditer) &&
|
2107
|
-
index_find(&existing, index, wd->path, 0) < 0)
|
2108
|
-
continue;
|
3376
|
+
return error;
|
3377
|
+
}
|
2109
3378
|
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
break;
|
2118
|
-
}
|
2119
|
-
}
|
3379
|
+
struct foreach_diff_data {
|
3380
|
+
git_index *index;
|
3381
|
+
const git_pathspec *pathspec;
|
3382
|
+
unsigned int flags;
|
3383
|
+
git_index_matched_path_cb cb;
|
3384
|
+
void *payload;
|
3385
|
+
};
|
2120
3386
|
|
2121
|
-
|
2122
|
-
|
2123
|
-
|
3387
|
+
static int apply_each_file(const git_diff_delta *delta, float progress, void *payload)
|
3388
|
+
{
|
3389
|
+
struct foreach_diff_data *data = payload;
|
3390
|
+
const char *match, *path;
|
3391
|
+
int error = 0;
|
2124
3392
|
|
2125
|
-
|
2126
|
-
if ((error = git_blob_create_fromworkdir(&blobid, repo, wd->path)) < 0)
|
2127
|
-
break;
|
3393
|
+
GIT_UNUSED(progress);
|
2128
3394
|
|
2129
|
-
|
2130
|
-
if ((entry = index_entry_dup(wd)) == NULL) {
|
2131
|
-
error = -1;
|
2132
|
-
break;
|
2133
|
-
}
|
2134
|
-
entry->oid = blobid;
|
3395
|
+
path = delta->old_file.path;
|
2135
3396
|
|
2136
|
-
|
2137
|
-
|
2138
|
-
|
2139
|
-
|
2140
|
-
|
3397
|
+
/* We only want those which match the pathspecs */
|
3398
|
+
if (!git_pathspec__match(
|
3399
|
+
&data->pathspec->pathspec, path, false, (bool)data->index->ignore_case,
|
3400
|
+
&match, NULL))
|
3401
|
+
return 0;
|
2141
3402
|
|
2142
|
-
|
3403
|
+
if (data->cb)
|
3404
|
+
error = data->cb(path, match, data->payload);
|
2143
3405
|
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
2149
|
-
|
3406
|
+
if (error > 0) /* skip this entry */
|
3407
|
+
return 0;
|
3408
|
+
if (error < 0) /* actual error */
|
3409
|
+
return error;
|
3410
|
+
|
3411
|
+
/* If the workdir item does not exist, remove it from the index. */
|
3412
|
+
if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
|
3413
|
+
error = git_index_remove_bypath(data->index, path);
|
3414
|
+
else
|
3415
|
+
error = git_index_add_bypath(data->index, delta->new_file.path);
|
3416
|
+
|
3417
|
+
return error;
|
3418
|
+
}
|
3419
|
+
|
3420
|
+
static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
|
3421
|
+
unsigned int flags,
|
3422
|
+
git_index_matched_path_cb cb, void *payload)
|
3423
|
+
{
|
3424
|
+
int error;
|
3425
|
+
git_diff *diff;
|
3426
|
+
git_pathspec ps;
|
3427
|
+
git_repository *repo;
|
3428
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
3429
|
+
struct foreach_diff_data data = {
|
3430
|
+
index,
|
3431
|
+
NULL,
|
3432
|
+
flags,
|
3433
|
+
cb,
|
3434
|
+
payload,
|
3435
|
+
};
|
3436
|
+
|
3437
|
+
assert(index);
|
3438
|
+
assert(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
|
3439
|
+
|
3440
|
+
repo = INDEX_OWNER(index);
|
3441
|
+
|
3442
|
+
if (!repo) {
|
3443
|
+
return create_index_error(-1,
|
3444
|
+
"cannot run update; the index is not backed up by a repository.");
|
2150
3445
|
}
|
2151
3446
|
|
2152
|
-
|
2153
|
-
|
3447
|
+
/*
|
3448
|
+
* We do the matching ourselves intead of passing the list to
|
3449
|
+
* diff because we want to tell the callback which one
|
3450
|
+
* matched, which we do not know if we ask diff to filter for us.
|
3451
|
+
*/
|
3452
|
+
if ((error = git_pathspec__init(&ps, paths)) < 0)
|
3453
|
+
return error;
|
2154
3454
|
|
2155
|
-
|
2156
|
-
|
2157
|
-
|
3455
|
+
opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
|
3456
|
+
if (action == INDEX_ACTION_ADDALL) {
|
3457
|
+
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
|
3458
|
+
GIT_DIFF_RECURSE_UNTRACKED_DIRS;
|
3459
|
+
|
3460
|
+
if (flags == GIT_INDEX_ADD_FORCE)
|
3461
|
+
opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
|
3462
|
+
}
|
3463
|
+
|
3464
|
+
if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
|
3465
|
+
goto cleanup;
|
3466
|
+
|
3467
|
+
data.pathspec = &ps;
|
3468
|
+
error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
|
3469
|
+
git_diff_free(diff);
|
2158
3470
|
|
3471
|
+
if (error) /* make sure error is set if callback stopped iteration */
|
3472
|
+
git_error_set_after_callback(error);
|
3473
|
+
|
3474
|
+
cleanup:
|
3475
|
+
git_pathspec__clear(&ps);
|
2159
3476
|
return error;
|
2160
3477
|
}
|
2161
3478
|
|
2162
|
-
enum {
|
2163
|
-
INDEX_ACTION_NONE = 0,
|
2164
|
-
INDEX_ACTION_UPDATE = 1,
|
2165
|
-
INDEX_ACTION_REMOVE = 2,
|
2166
|
-
};
|
2167
|
-
|
2168
3479
|
static int index_apply_to_all(
|
2169
3480
|
git_index *index,
|
2170
3481
|
int action,
|
@@ -2174,13 +3485,13 @@ static int index_apply_to_all(
|
|
2174
3485
|
{
|
2175
3486
|
int error = 0;
|
2176
3487
|
size_t i;
|
2177
|
-
|
3488
|
+
git_pathspec ps;
|
2178
3489
|
const char *match;
|
2179
3490
|
git_buf path = GIT_BUF_INIT;
|
2180
3491
|
|
2181
3492
|
assert(index);
|
2182
3493
|
|
2183
|
-
if ((error =
|
3494
|
+
if ((error = git_pathspec__init(&ps, paths)) < 0)
|
2184
3495
|
return error;
|
2185
3496
|
|
2186
3497
|
git_vector_sort(&index->entries);
|
@@ -2189,8 +3500,9 @@ static int index_apply_to_all(
|
|
2189
3500
|
git_index_entry *entry = git_vector_get(&index->entries, i);
|
2190
3501
|
|
2191
3502
|
/* check if path actually matches */
|
2192
|
-
if (!
|
2193
|
-
&ps.pathspec, entry->path, false, index->ignore_case,
|
3503
|
+
if (!git_pathspec__match(
|
3504
|
+
&ps.pathspec, entry->path, false, (bool)index->ignore_case,
|
3505
|
+
&match, NULL))
|
2194
3506
|
continue;
|
2195
3507
|
|
2196
3508
|
/* issue notification callback if requested */
|
@@ -2199,11 +3511,8 @@ static int index_apply_to_all(
|
|
2199
3511
|
error = 0;
|
2200
3512
|
continue;
|
2201
3513
|
}
|
2202
|
-
if (error < 0)
|
2203
|
-
giterr_clear();
|
2204
|
-
error = GIT_EUSER;
|
3514
|
+
if (error < 0) /* return < 0 means abort */
|
2205
3515
|
break;
|
2206
|
-
}
|
2207
3516
|
}
|
2208
3517
|
|
2209
3518
|
/* index manipulation may alter entry, so don't depend on it */
|
@@ -2217,7 +3526,7 @@ static int index_apply_to_all(
|
|
2217
3526
|
error = git_index_add_bypath(index, path.ptr);
|
2218
3527
|
|
2219
3528
|
if (error == GIT_ENOTFOUND) {
|
2220
|
-
|
3529
|
+
git_error_clear();
|
2221
3530
|
|
2222
3531
|
error = git_index_remove_bypath(index, path.ptr);
|
2223
3532
|
|
@@ -2230,14 +3539,14 @@ static int index_apply_to_all(
|
|
2230
3539
|
i--; /* back up foreach if we removed this */
|
2231
3540
|
break;
|
2232
3541
|
default:
|
2233
|
-
|
3542
|
+
git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action);
|
2234
3543
|
error = -1;
|
2235
3544
|
break;
|
2236
3545
|
}
|
2237
3546
|
}
|
2238
3547
|
|
2239
|
-
|
2240
|
-
|
3548
|
+
git_buf_dispose(&path);
|
3549
|
+
git_pathspec__clear(&ps);
|
2241
3550
|
|
2242
3551
|
return error;
|
2243
3552
|
}
|
@@ -2248,8 +3557,13 @@ int git_index_remove_all(
|
|
2248
3557
|
git_index_matched_path_cb cb,
|
2249
3558
|
void *payload)
|
2250
3559
|
{
|
2251
|
-
|
3560
|
+
int error = index_apply_to_all(
|
2252
3561
|
index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
|
3562
|
+
|
3563
|
+
if (error) /* make sure error is set if callback stopped iteration */
|
3564
|
+
git_error_set_after_callback(error);
|
3565
|
+
|
3566
|
+
return error;
|
2253
3567
|
}
|
2254
3568
|
|
2255
3569
|
int git_index_update_all(
|
@@ -2258,6 +3572,131 @@ int git_index_update_all(
|
|
2258
3572
|
git_index_matched_path_cb cb,
|
2259
3573
|
void *payload)
|
2260
3574
|
{
|
2261
|
-
|
2262
|
-
|
3575
|
+
int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
|
3576
|
+
if (error) /* make sure error is set if callback stopped iteration */
|
3577
|
+
git_error_set_after_callback(error);
|
3578
|
+
|
3579
|
+
return error;
|
3580
|
+
}
|
3581
|
+
|
3582
|
+
int git_index_snapshot_new(git_vector *snap, git_index *index)
|
3583
|
+
{
|
3584
|
+
int error;
|
3585
|
+
|
3586
|
+
GIT_REFCOUNT_INC(index);
|
3587
|
+
|
3588
|
+
git_atomic_inc(&index->readers);
|
3589
|
+
git_vector_sort(&index->entries);
|
3590
|
+
|
3591
|
+
error = git_vector_dup(snap, &index->entries, index->entries._cmp);
|
3592
|
+
|
3593
|
+
if (error < 0)
|
3594
|
+
git_index_snapshot_release(snap, index);
|
3595
|
+
|
3596
|
+
return error;
|
3597
|
+
}
|
3598
|
+
|
3599
|
+
void git_index_snapshot_release(git_vector *snap, git_index *index)
|
3600
|
+
{
|
3601
|
+
git_vector_free(snap);
|
3602
|
+
|
3603
|
+
git_atomic_dec(&index->readers);
|
3604
|
+
|
3605
|
+
git_index_free(index);
|
3606
|
+
}
|
3607
|
+
|
3608
|
+
int git_index_snapshot_find(
|
3609
|
+
size_t *out, git_vector *entries, git_vector_cmp entry_srch,
|
3610
|
+
const char *path, size_t path_len, int stage)
|
3611
|
+
{
|
3612
|
+
return index_find_in_entries(out, entries, entry_srch, path, path_len, stage);
|
3613
|
+
}
|
3614
|
+
|
3615
|
+
int git_indexwriter_init(
|
3616
|
+
git_indexwriter *writer,
|
3617
|
+
git_index *index)
|
3618
|
+
{
|
3619
|
+
int error;
|
3620
|
+
|
3621
|
+
GIT_REFCOUNT_INC(index);
|
3622
|
+
|
3623
|
+
writer->index = index;
|
3624
|
+
|
3625
|
+
if (!index->index_file_path)
|
3626
|
+
return create_index_error(-1,
|
3627
|
+
"failed to write index: The index is in-memory only");
|
3628
|
+
|
3629
|
+
if ((error = git_filebuf_open(
|
3630
|
+
&writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) {
|
3631
|
+
|
3632
|
+
if (error == GIT_ELOCKED)
|
3633
|
+
git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process");
|
3634
|
+
|
3635
|
+
return error;
|
3636
|
+
}
|
3637
|
+
|
3638
|
+
writer->should_write = 1;
|
3639
|
+
|
3640
|
+
return 0;
|
3641
|
+
}
|
3642
|
+
|
3643
|
+
int git_indexwriter_init_for_operation(
|
3644
|
+
git_indexwriter *writer,
|
3645
|
+
git_repository *repo,
|
3646
|
+
unsigned int *checkout_strategy)
|
3647
|
+
{
|
3648
|
+
git_index *index;
|
3649
|
+
int error;
|
3650
|
+
|
3651
|
+
if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
|
3652
|
+
(error = git_indexwriter_init(writer, index)) < 0)
|
3653
|
+
return error;
|
3654
|
+
|
3655
|
+
writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0;
|
3656
|
+
*checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX;
|
3657
|
+
|
3658
|
+
return 0;
|
3659
|
+
}
|
3660
|
+
|
3661
|
+
int git_indexwriter_commit(git_indexwriter *writer)
|
3662
|
+
{
|
3663
|
+
int error;
|
3664
|
+
git_oid checksum = {{ 0 }};
|
3665
|
+
|
3666
|
+
if (!writer->should_write)
|
3667
|
+
return 0;
|
3668
|
+
|
3669
|
+
git_vector_sort(&writer->index->entries);
|
3670
|
+
git_vector_sort(&writer->index->reuc);
|
3671
|
+
|
3672
|
+
if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
|
3673
|
+
git_indexwriter_cleanup(writer);
|
3674
|
+
return error;
|
3675
|
+
}
|
3676
|
+
|
3677
|
+
if ((error = git_filebuf_commit(&writer->file)) < 0)
|
3678
|
+
return error;
|
3679
|
+
|
3680
|
+
if ((error = git_futils_filestamp_check(
|
3681
|
+
&writer->index->stamp, writer->index->index_file_path)) < 0) {
|
3682
|
+
git_error_set(GIT_ERROR_OS, "could not read index timestamp");
|
3683
|
+
return -1;
|
3684
|
+
}
|
3685
|
+
|
3686
|
+
writer->index->dirty = 0;
|
3687
|
+
writer->index->on_disk = 1;
|
3688
|
+
git_oid_cpy(&writer->index->checksum, &checksum);
|
3689
|
+
|
3690
|
+
git_index_free(writer->index);
|
3691
|
+
writer->index = NULL;
|
3692
|
+
|
3693
|
+
return 0;
|
3694
|
+
}
|
3695
|
+
|
3696
|
+
void git_indexwriter_cleanup(git_indexwriter *writer)
|
3697
|
+
{
|
3698
|
+
git_filebuf_cleanup(&writer->file);
|
3699
|
+
|
3700
|
+
git_index_free(writer->index);
|
3701
|
+
writer->index = NULL;
|
2263
3702
|
}
|