source src/apply.c
| Line | Flow | Count | Block(s) | Source |
|---|---|---|---|---|
| 1 | - | /* | ||
| 2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
| 3 | - | * | ||
| 4 | - | * This file is part of libgit2, distributed under the GNU GPL v2 with | ||
| 5 | - | * a Linking Exception. For full terms see the included COPYING file. | ||
| 6 | - | */ | ||
| 7 | - | |||
| 8 | - | #include "apply.h" | ||
| 9 | - | |||
| 10 | - | #include "git2/apply.h" | ||
| 11 | - | #include "git2/patch.h" | ||
| 12 | - | #include "git2/filter.h" | ||
| 13 | - | #include "git2/blob.h" | ||
| 14 | - | #include "git2/index.h" | ||
| 15 | - | #include "git2/checkout.h" | ||
| 16 | - | #include "git2/repository.h" | ||
| 17 | - | #include "array.h" | ||
| 18 | - | #include "patch.h" | ||
| 19 | - | #include "futils.h" | ||
| 20 | - | #include "delta.h" | ||
| 21 | - | #include "zstream.h" | ||
| 22 | - | #include "reader.h" | ||
| 23 | - | #include "index.h" | ||
| 24 | - | |||
| 25 | - | typedef struct { | ||
| 26 | - | /* The lines that we allocate ourself are allocated out of the pool. | ||
| 27 | - | * (Lines may have been allocated out of the diff.) | ||
| 28 | - | */ | ||
| 29 | - | git_pool pool; | ||
| 30 | - | git_vector lines; | ||
| 31 | - | } patch_image; | ||
| 32 | - | |||
| 33 | - | static int apply_err(const char *fmt, ...) GIT_FORMAT_PRINTF(1, 2); | ||
| 34 | 10 | 2 | static int apply_err(const char *fmt, ...) | |
| 35 | - | { | ||
| 36 | - | va_list ap; | ||
| 37 | - | |||
| 38 | 10 | 2 | va_start(ap, fmt); | |
| 39 | 10 | 2 | git_error_vset(GIT_ERROR_PATCH, fmt, ap); | |
| 40 | 10 | 3 | va_end(ap); | |
| 41 | - | |||
| 42 | 10 | 3 | return GIT_EAPPLYFAIL; | |
| 43 | - | } | ||
| 44 | - | |||
| 45 | 1303 | 2 | static void patch_line_init( | |
| 46 | - | git_diff_line *out, | ||
| 47 | - | const char *in, | ||
| 48 | - | size_t in_len, | ||
| 49 | - | size_t in_offset) | ||
| 50 | - | { | ||
| 51 | 1303 | 2 | out->content = in; | |
| 52 | 1303 | 2 | out->content_len = in_len; | |
| 53 | 1303 | 2 | out->content_offset = in_offset; | |
| 54 | 1303 | 2 | } | |
| 55 | - | |||
| 56 | - | #define PATCH_IMAGE_INIT { GIT_POOL_INIT, GIT_VECTOR_INIT } | ||
| 57 | - | |||
| 58 | ![]() |
123 | 2 | static int patch_image_init_fromstr( |
| 59 | - | patch_image *out, const char *in, size_t in_len) | ||
| 60 | - | { | ||
| 61 | - | git_diff_line *line; | ||
| 62 | - | const char *start, *end; | ||
| 63 | - | |||
| 64 | 123 | 2 | memset(out, 0x0, sizeof(patch_image)); | |
| 65 | - | |||
| 66 | 123 | 2,3 | if (git_pool_init(&out->pool, sizeof(git_diff_line)) < 0) | |
| 67 | ##### | 4 | return -1; | |
| 68 | - | |||
| 69 | 1426 | 5,17,18 | for (start = in; start < in + in_len; start = end) { | |
| 70 | 1303 | 6 | end = memchr(start, '\n', in_len - (start - in)); | |
| 71 | - | |||
| 72 | 1303 | 6 | if (end == NULL) | |
| 73 | 2 | 7 | end = in + in_len; | |
| 74 | - | |||
| 75 | 1301 | 8 | else if (end < in + in_len) | |
| 76 | 1301 | 9 | end++; | |
| 77 | - | |||
| 78 | 1303 | 10 | line = git_pool_mallocz(&out->pool, 1); | |
| 79 | 1303 | 11,12 | GIT_ERROR_CHECK_ALLOC(line); | |
| 80 | - | |||
| 81 | 1303 | 13,14 | if (git_vector_insert(&out->lines, line) < 0) | |
| 82 | ##### | 15 | return -1; | |
| 83 | - | |||
| 84 | 1303 | 16 | patch_line_init(line, start, (end - start), (start - in)); | |
| 85 | - | } | ||
| 86 | - | |||
| 87 | 123 | 19 | return 0; | |
| 88 | - | } | ||
| 89 | - | |||
| 90 | 443 | 2 | static void patch_image_free(patch_image *image) | |
| 91 | - | { | ||
| 92 | 443 | 2 | if (image == NULL) | |
| 93 | 443 | 3,6 | return; | |
| 94 | - | |||
| 95 | 443 | 4 | git_pool_clear(&image->pool); | |
| 96 | 443 | 5 | git_vector_free(&image->lines); | |
| 97 | - | } | ||
| 98 | - | |||
| 99 | ![]() |
148 | 2 | static bool match_hunk( |
| 100 | - | patch_image *image, | ||
| 101 | - | patch_image *preimage, | ||
| 102 | - | size_t linenum) | ||
| 103 | - | { | ||
| 104 | 148 | 2 | bool match = 0; | |
| 105 | - | size_t i; | ||
| 106 | - | |||
| 107 | - | /* Ensure this hunk is within the image boundaries. */ | ||
| 108 | 148 | 2,4 | if (git_vector_length(&preimage->lines) + linenum > | |
| 109 | 148 | 3 | git_vector_length(&image->lines)) | |
| 110 | ##### | 5 | return 0; | |
| 111 | - | |||
| 112 | 148 | 6 | match = 1; | |
| 113 | - | |||
| 114 | - | /* Check exact match. */ | ||
| 115 | 565 | 6,12-14 | for (i = 0; i < git_vector_length(&preimage->lines); i++) { | |
| 116 | 421 | 7 | git_diff_line *preimage_line = git_vector_get(&preimage->lines, i); | |
| 117 | 421 | 8 | git_diff_line *image_line = git_vector_get(&image->lines, linenum + i); | |
| 118 | - | |||
| 119 | 421 | 9,10 | if (preimage_line->content_len != image_line->content_len || | |
| 120 | 418 | 10 | memcmp(preimage_line->content, image_line->content, image_line->content_len) != 0) { | |
| 121 | 4 | 11 | match = 0; | |
| 122 | 4 | 11 | break; | |
| 123 | - | } | ||
| 124 | - | } | ||
| 125 | - | |||
| 126 | 148 | 15 | return match; | |
| 127 | - | } | ||
| 128 | - | |||
| 129 | 148 | 2 | static bool find_hunk_linenum( | |
| 130 | - | size_t *out, | ||
| 131 | - | patch_image *image, | ||
| 132 | - | patch_image *preimage, | ||
| 133 | - | size_t linenum) | ||
| 134 | - | { | ||
| 135 | 148 | 2 | size_t max = git_vector_length(&image->lines); | |
| 136 | - | bool match; | ||
| 137 | - | |||
| 138 | 148 | 3 | if (linenum > max) | |
| 139 | ##### | 4 | linenum = max; | |
| 140 | - | |||
| 141 | 148 | 5 | match = match_hunk(image, preimage, linenum); | |
| 142 | - | |||
| 143 | 148 | 6 | *out = linenum; | |
| 144 | 148 | 6 | return match; | |
| 145 | - | } | ||
| 146 | - | |||
| 147 | ![]() |
144 | 2 | static int update_hunk( |
| 148 | - | patch_image *image, | ||
| 149 | - | size_t linenum, | ||
| 150 | - | patch_image *preimage, | ||
| 151 | - | patch_image *postimage) | ||
| 152 | - | { | ||
| 153 | 144 | 2 | size_t postlen = git_vector_length(&postimage->lines); | |
| 154 | 144 | 3 | size_t prelen = git_vector_length(&preimage->lines); | |
| 155 | - | size_t i; | ||
| 156 | 144 | 4 | int error = 0; | |
| 157 | - | |||
| 158 | 144 | 4 | if (postlen > prelen) | |
| 159 | 31 | 5 | error = git_vector_insert_null( | |
| 160 | - | &image->lines, linenum, (postlen - prelen)); | ||
| 161 | 113 | 6 | else if (prelen > postlen) | |
| 162 | 15 | 7 | error = git_vector_remove_range( | |
| 163 | - | &image->lines, linenum, (prelen - postlen)); | ||
| 164 | - | |||
| 165 | 144 | 8 | if (error) { | |
| 166 | ##### | 9 | git_error_set_oom(); | |
| 167 | ##### | 10 | return -1; | |
| 168 | - | } | ||
| 169 | - | |||
| 170 | 587 | 11,13-15 | for (i = 0; i < git_vector_length(&postimage->lines); i++) { | |
| 171 | 443 | 12,13 | image->lines.contents[linenum + i] = | |
| 172 | 443 | 12 | git_vector_get(&postimage->lines, i); | |
| 173 | - | } | ||
| 174 | - | |||
| 175 | 144 | 16 | return 0; | |
| 176 | - | } | ||
| 177 | - | |||
| 178 | - | typedef struct { | ||
| 179 | - | git_apply_options opts; | ||
| 180 | - | size_t skipped_new_lines; | ||
| 181 | - | size_t skipped_old_lines; | ||
| 182 | - | } apply_hunks_ctx; | ||
| 183 | - | |||
| 184 | ![]() |
160 | 2 | static int apply_hunk( |
| 185 | - | patch_image *image, | ||
| 186 | - | git_patch *patch, | ||
| 187 | - | git_patch_hunk *hunk, | ||
| 188 | - | apply_hunks_ctx *ctx) | ||
| 189 | - | { | ||
| 190 | 160 | 2 | patch_image preimage = PATCH_IMAGE_INIT, postimage = PATCH_IMAGE_INIT; | |
| 191 | - | size_t line_num, i; | ||
| 192 | 160 | 2 | int error = 0; | |
| 193 | - | |||
| 194 | 160 | 2 | if (ctx->opts.hunk_cb) { | |
| 195 | 23 | 3 | error = ctx->opts.hunk_cb(&hunk->hunk, ctx->opts.payload); | |
| 196 | - | |||
| 197 | 23 | 4 | if (error) { | |
| 198 | 12 | 5 | if (error > 0) { | |
| 199 | 8 | 6 | ctx->skipped_new_lines += hunk->hunk.new_lines; | |
| 200 | 8 | 6 | ctx->skipped_old_lines += hunk->hunk.old_lines; | |
| 201 | 8 | 6 | error = 0; | |
| 202 | - | } | ||
| 203 | - | |||
| 204 | 12 | 7 | goto done; | |
| 205 | - | } | ||
| 206 | - | } | ||
| 207 | - | |||
| 208 | 800 | 8,39,40 | for (i = 0; i < hunk->line_count; i++) { | |
| 209 | 652 | 9 | size_t linenum = hunk->line_start + i; | |
| 210 | 652 | 9-11 | git_diff_line *line = git_array_get(patch->lines, linenum), *prev; | |
| 211 | - | |||
| 212 | 652 | 12 | if (!line) { | |
| 213 | ##### | 13 | error = apply_err("preimage does not contain line %"PRIuZ, linenum); | |
| 214 | ##### | 14 | goto done; | |
| 215 | - | } | ||
| 216 | - | |||
| 217 | 652 | 15 | switch (line->origin) { | |
| 218 | - | case GIT_DIFF_LINE_CONTEXT_EOFNL: | ||
| 219 | - | case GIT_DIFF_LINE_DEL_EOFNL: | ||
| 220 | - | case GIT_DIFF_LINE_ADD_EOFNL: | ||
| 221 | 6 | 16-21 | prev = i ? git_array_get(patch->lines, linenum - 1) : NULL; | |
| 222 | 6 | 22,23 | if (prev && prev->content[prev->content_len - 1] == '\n') | |
| 223 | 1 | 24 | prev->content_len -= 1; | |
| 224 | 6 | 25 | break; | |
| 225 | - | case GIT_DIFF_LINE_CONTEXT: | ||
| 226 | 229 | 26-29 | if ((error = git_vector_insert(&preimage.lines, line)) < 0 || | |
| 227 | - | (error = git_vector_insert(&postimage.lines, line)) < 0) | ||
| 228 | - | goto done; | ||
| 229 | 229 | 30 | break; | |
| 230 | - | case GIT_DIFF_LINE_DELETION: | ||
| 231 | 195 | 31,32 | if ((error = git_vector_insert(&preimage.lines, line)) < 0) | |
| 232 | ##### | 33 | goto done; | |
| 233 | 195 | 34 | break; | |
| 234 | - | case GIT_DIFF_LINE_ADDITION: | ||
| 235 | 222 | 35,36 | if ((error = git_vector_insert(&postimage.lines, line)) < 0) | |
| 236 | ##### | 37 | goto done; | |
| 237 | 222 | 38 | break; | |
| 238 | - | } | ||
| 239 | - | } | ||
| 240 | - | |||
| 241 | 148 | 41 | if (hunk->hunk.new_start) { | |
| 242 | 141 | 42,42,42 | line_num = hunk->hunk.new_start - | |
| 243 | 141 | 42,42 | ctx->skipped_new_lines + | |
| 244 | 141 | 42,42 | ctx->skipped_old_lines - | |
| 245 | - | 1; | ||
| 246 | - | } else { | ||
| 247 | 7 | 43 | line_num = 0; | |
| 248 | - | } | ||
| 249 | - | |||
| 250 | 148 | 44,45 | if (!find_hunk_linenum(&line_num, image, &preimage, line_num)) { | |
| 251 | 4 | 46 | error = apply_err("hunk at line %d did not apply", | |
| 252 | - | hunk->hunk.new_start); | ||
| 253 | 4 | 47 | goto done; | |
| 254 | - | } | ||
| 255 | - | |||
| 256 | 144 | 48 | error = update_hunk(image, line_num, &preimage, &postimage); | |
| 257 | - | |||
| 258 | - | done: | ||
| 259 | 160 | 49 | patch_image_free(&preimage); | |
| 260 | 160 | 50 | patch_image_free(&postimage); | |
| 261 | - | |||
| 262 | 160 | 51 | return error; | |
| 263 | - | } | ||
| 264 | - | |||
| 265 | ![]() |
123 | 2 | static int apply_hunks( |
| 266 | - | git_buf *out, | ||
| 267 | - | const char *source, | ||
| 268 | - | size_t source_len, | ||
| 269 | - | git_patch *patch, | ||
| 270 | - | apply_hunks_ctx *ctx) | ||
| 271 | - | { | ||
| 272 | - | git_patch_hunk *hunk; | ||
| 273 | - | git_diff_line *line; | ||
| 274 | - | patch_image image; | ||
| 275 | - | size_t i; | ||
| 276 | 123 | 2 | int error = 0; | |
| 277 | - | |||
| 278 | 123 | 2,3 | if ((error = patch_image_init_fromstr(&image, source, source_len)) < 0) | |
| 279 | ##### | 4 | goto done; | |
| 280 | - | |||
| 281 | 275 | 5,9-11 | git_array_foreach(patch->hunks, i, hunk) { | |
| 282 | 160 | 6,7 | if ((error = apply_hunk(&image, patch, hunk, ctx)) < 0) | |
| 283 | 8 | 8 | goto done; | |
| 284 | - | } | ||
| 285 | - | |||
| 286 | 1383 | 12,14-16 | git_vector_foreach(&image.lines, i, line) | |
| 287 | 1268 | 13 | git_buf_put(out, line->content, line->content_len); | |
| 288 | - | |||
| 289 | - | done: | ||
| 290 | 123 | 17 | patch_image_free(&image); | |
| 291 | - | |||
| 292 | 123 | 18 | return error; | |
| 293 | - | } | ||
| 294 | - | |||
| 295 | ![]() |
24 | 2 | static int apply_binary_delta( |
| 296 | - | git_buf *out, | ||
| 297 | - | const char *source, | ||
| 298 | - | size_t source_len, | ||
| 299 | - | git_diff_binary_file *binary_file) | ||
| 300 | - | { | ||
| 301 | 24 | 2 | git_buf inflated = GIT_BUF_INIT; | |
| 302 | 24 | 2 | int error = 0; | |
| 303 | - | |||
| 304 | - | /* no diff means identical contents */ | ||
| 305 | 24 | 2 | if (binary_file->datalen == 0) | |
| 306 | ##### | 3 | return git_buf_put(out, source, source_len); | |
| 307 | - | |||
| 308 | 24 | 4,4 | error = git_zstream_inflatebuf(&inflated, | |
| 309 | 24 | 4 | binary_file->data, binary_file->datalen); | |
| 310 | - | |||
| 311 | 24 | 5,6 | if (!error && inflated.size != binary_file->inflatedlen) { | |
| 312 | ##### | 7 | error = apply_err("inflated delta does not match expected length"); | |
| 313 | ##### | 8 | git_buf_dispose(out); | |
| 314 | - | } | ||
| 315 | - | |||
| 316 | 24 | 9 | if (error < 0) | |
| 317 | ##### | 10 | goto done; | |
| 318 | - | |||
| 319 | 24 | 11 | if (binary_file->type == GIT_DIFF_BINARY_DELTA) { | |
| 320 | - | void *data; | ||
| 321 | - | size_t data_len; | ||
| 322 | - | |||
| 323 | 11 | 12,12 | error = git_delta_apply(&data, &data_len, (void *)source, source_len, | |
| 324 | 11 | 12 | (void *)inflated.ptr, inflated.size); | |
| 325 | - | |||
| 326 | 11 | 13 | out->ptr = data; | |
| 327 | 11 | 13 | out->size = data_len; | |
| 328 | 11 | 13 | out->asize = data_len; | |
| 329 | - | } | ||
| 330 | 13 | 14 | else if (binary_file->type == GIT_DIFF_BINARY_LITERAL) { | |
| 331 | 13 | 15 | git_buf_swap(out, &inflated); | |
| 332 | - | } | ||
| 333 | - | else { | ||
| 334 | ##### | 16 | error = apply_err("unknown binary delta type"); | |
| 335 | ##### | 17 | goto done; | |
| 336 | - | } | ||
| 337 | - | |||
| 338 | - | done: | ||
| 339 | 24 | 18 | git_buf_dispose(&inflated); | |
| 340 | 24 | 19 | return error; | |
| 341 | - | } | ||
| 342 | - | |||
| 343 | ![]() |
13 | 2 | static int apply_binary( |
| 344 | - | git_buf *out, | ||
| 345 | - | const char *source, | ||
| 346 | - | size_t source_len, | ||
| 347 | - | git_patch *patch) | ||
| 348 | - | { | ||
| 349 | 13 | 2 | git_buf reverse = GIT_BUF_INIT; | |
| 350 | 13 | 2 | int error = 0; | |
| 351 | - | |||
| 352 | 13 | 2 | if (!patch->binary.contains_data) { | |
| 353 | ##### | 3 | error = apply_err("patch does not contain binary data"); | |
| 354 | ##### | 4 | goto done; | |
| 355 | - | } | ||
| 356 | - | |||
| 357 | 13 | 5,6 | if (!patch->binary.old_file.datalen && !patch->binary.new_file.datalen) | |
| 358 | 1 | 7 | goto done; | |
| 359 | - | |||
| 360 | - | /* first, apply the new_file delta to the given source */ | ||
| 361 | 12 | 8,9 | if ((error = apply_binary_delta(out, source, source_len, | |
| 362 | - | &patch->binary.new_file)) < 0) | ||
| 363 | ##### | 10 | goto done; | |
| 364 | - | |||
| 365 | - | /* second, apply the old_file delta to sanity check the result */ | ||
| 366 | 12 | 11,12 | if ((error = apply_binary_delta(&reverse, out->ptr, out->size, | |
| 367 | - | &patch->binary.old_file)) < 0) | ||
| 368 | 1 | 13 | goto done; | |
| 369 | - | |||
| 370 | - | /* Verify that the resulting file with the reverse patch applied matches the source file */ | ||
| 371 | 11 | 14,15 | if (source_len != reverse.size || | |
| 372 | 9 | 16 | (source_len && memcmp(source, reverse.ptr, source_len) != 0)) { | |
| 373 | 1 | 17 | error = apply_err("binary patch did not apply cleanly"); | |
| 374 | 1 | 18 | goto done; | |
| 375 | - | } | ||
| 376 | - | |||
| 377 | - | done: | ||
| 378 | 13 | 19 | if (error < 0) | |
| 379 | 2 | 20 | git_buf_dispose(out); | |
| 380 | - | |||
| 381 | 13 | 21 | git_buf_dispose(&reverse); | |
| 382 | 13 | 22 | return error; | |
| 383 | - | } | ||
| 384 | - | |||
| 385 | ![]() |
150 | 2 | int git_apply__patch( |
| 386 | - | git_buf *contents_out, | ||
| 387 | - | char **filename_out, | ||
| 388 | - | unsigned int *mode_out, | ||
| 389 | - | const char *source, | ||
| 390 | - | size_t source_len, | ||
| 391 | - | git_patch *patch, | ||
| 392 | - | const git_apply_options *given_opts) | ||
| 393 | - | { | ||
| 394 | 150 | 2 | apply_hunks_ctx ctx = { GIT_APPLY_OPTIONS_INIT }; | |
| 395 | 150 | 2 | char *filename = NULL; | |
| 396 | 150 | 2 | unsigned int mode = 0; | |
| 397 | 150 | 2 | int error = 0; | |
| 398 | - | |||
| 399 | 150 | 2-8 | assert(contents_out && filename_out && mode_out && (source || !source_len) && patch); | |
| 400 | - | |||
| 401 | 150 | 9 | if (given_opts) | |
| 402 | 91 | 10 | memcpy(&ctx.opts, given_opts, sizeof(git_apply_options)); | |
| 403 | - | |||
| 404 | 150 | 11 | *filename_out = NULL; | |
| 405 | 150 | 11 | *mode_out = 0; | |
| 406 | - | |||
| 407 | 150 | 11 | if (patch->delta->status != GIT_DELTA_DELETED) { | |
| 408 | 146 | 12 | const git_diff_file *newfile = &patch->delta->new_file; | |
| 409 | - | |||
| 410 | 146 | 12 | filename = git__strdup(newfile->path); | |
| 411 | 146 | 13-16 | mode = newfile->mode ? | |
| 412 | 136 | 14 | newfile->mode : GIT_FILEMODE_BLOB; | |
| 413 | - | } | ||
| 414 | - | |||
| 415 | 150 | 17 | if (patch->delta->flags & GIT_DIFF_FLAG_BINARY) | |
| 416 | 13 | 18 | error = apply_binary(contents_out, source, source_len, patch); | |
| 417 | 137 | 19 | else if (patch->hunks.size) | |
| 418 | 123 | 20 | error = apply_hunks(contents_out, source, source_len, patch, &ctx); | |
| 419 | - | else | ||
| 420 | 14 | 21 | error = git_buf_put(contents_out, source, source_len); | |
| 421 | - | |||
| 422 | 150 | 22 | if (error) | |
| 423 | 10 | 23 | goto done; | |
| 424 | - | |||
| 425 | 140 | 24,26 | if (patch->delta->status == GIT_DELTA_DELETED && | |
| 426 | 4 | 25 | git_buf_len(contents_out) > 0) { | |
| 427 | ##### | 27 | error = apply_err("removal patch leaves file contents"); | |
| 428 | ##### | 28 | goto done; | |
| 429 | - | } | ||
| 430 | - | |||
| 431 | 140 | 29 | *filename_out = filename; | |
| 432 | 140 | 29 | *mode_out = mode; | |
| 433 | - | |||
| 434 | - | done: | ||
| 435 | 150 | 30 | if (error < 0) | |
| 436 | 10 | 31 | git__free(filename); | |
| 437 | - | |||
| 438 | 150 | 32 | return error; | |
| 439 | - | } | ||
| 440 | - | |||
| 441 | ![]() |
94 | 2 | static int apply_one( |
| 442 | - | git_repository *repo, | ||
| 443 | - | git_reader *preimage_reader, | ||
| 444 | - | git_index *preimage, | ||
| 445 | - | git_reader *postimage_reader, | ||
| 446 | - | git_index *postimage, | ||
| 447 | - | git_diff *diff, | ||
| 448 | - | git_strmap *removed_paths, | ||
| 449 | - | size_t i, | ||
| 450 | - | const git_apply_options *opts) | ||
| 451 | - | { | ||
| 452 | 94 | 2 | git_patch *patch = NULL; | |
| 453 | 94 | 2 | git_buf pre_contents = GIT_BUF_INIT, post_contents = GIT_BUF_INIT; | |
| 454 | - | const git_diff_delta *delta; | ||
| 455 | 94 | 2 | char *filename = NULL; | |
| 456 | - | unsigned int mode; | ||
| 457 | - | git_oid pre_id, post_id; | ||
| 458 | - | git_filemode_t pre_filemode; | ||
| 459 | - | git_index_entry pre_entry, post_entry; | ||
| 460 | 94 | 2 | bool skip_preimage = false; | |
| 461 | - | int error; | ||
| 462 | - | |||
| 463 | 94 | 2,3 | if ((error = git_patch_from_diff(&patch, diff, i)) < 0) | |
| 464 | ##### | 4 | goto done; | |
| 465 | - | |||
| 466 | 94 | 5 | delta = git_patch_get_delta(patch); | |
| 467 | - | |||
| 468 | 94 | 6 | if (opts->delta_cb) { | |
| 469 | 4 | 7 | error = opts->delta_cb(delta, opts->payload); | |
| 470 | - | |||
| 471 | 4 | 8 | if (error) { | |
| 472 | 2 | 9 | if (error > 0) | |
| 473 | 1 | 10 | error = 0; | |
| 474 | - | |||
| 475 | 2 | 11 | goto done; | |
| 476 | - | } | ||
| 477 | - | } | ||
| 478 | - | |||
| 479 | - | /* | ||
| 480 | - | * Ensure that the file has not been deleted or renamed if we're | ||
| 481 | - | * applying a modification delta. | ||
| 482 | - | */ | ||
| 483 | 92 | 12,13 | if (delta->status != GIT_DELTA_RENAMED && | |
| 484 | 79 | 13 | delta->status != GIT_DELTA_ADDED) { | |
| 485 | 72 | 14,15 | if (git_strmap_exists(removed_paths, delta->old_file.path)) { | |
| 486 | 2 | 16 | error = apply_err("path '%s' has been renamed or deleted", delta->old_file.path); | |
| 487 | 2 | 17 | goto done; | |
| 488 | - | } | ||
| 489 | - | } | ||
| 490 | - | |||
| 491 | - | /* | ||
| 492 | - | * We may be applying a second delta to an already seen file. If so, | ||
| 493 | - | * use the already modified data in the postimage instead of the | ||
| 494 | - | * content from the index or working directory. (Don't do this in | ||
| 495 | - | * the case of a rename, which must be specified before additional | ||
| 496 | - | * deltas since we apply deltas to the target filename.) | ||
| 497 | - | */ | ||
| 498 | 90 | 18 | if (delta->status != GIT_DELTA_RENAMED) { | |
| 499 | 77 | 19,20 | if ((error = git_reader_read(&pre_contents, &pre_id, &pre_filemode, | |
| 500 | - | postimage_reader, delta->old_file.path)) == 0) { | ||
| 501 | 5 | 21 | skip_preimage = true; | |
| 502 | 72 | 22 | } else if (error == GIT_ENOTFOUND) { | |
| 503 | 72 | 23 | git_error_clear(); | |
| 504 | 72 | 24 | error = 0; | |
| 505 | - | } else { | ||
| 506 | ##### | 25 | goto done; | |
| 507 | - | } | ||
| 508 | - | } | ||
| 509 | - | |||
| 510 | 90 | 26,27 | if (!skip_preimage && delta->status != GIT_DELTA_ADDED) { | |
| 511 | 78 | 28 | error = git_reader_read(&pre_contents, &pre_id, &pre_filemode, | |
| 512 | - | preimage_reader, delta->old_file.path); | ||
| 513 | - | |||
| 514 | - | /* ENOTFOUND means the preimage was not found; apply failed. */ | ||
| 515 | 78 | 29 | if (error == GIT_ENOTFOUND) | |
| 516 | 2 | 30 | error = GIT_EAPPLYFAIL; | |
| 517 | - | |||
| 518 | - | /* When applying to BOTH, the index did not match the workdir. */ | ||
| 519 | 78 | 31 | if (error == GIT_READER_MISMATCH) | |
| 520 | 3 | 32 | error = apply_err("%s: does not match index", delta->old_file.path); | |
| 521 | - | |||
| 522 | 78 | 33 | if (error < 0) | |
| 523 | 5 | 34 | goto done; | |
| 524 | - | |||
| 525 | - | /* | ||
| 526 | - | * We need to populate the preimage data structure with the | ||
| 527 | - | * contents that we are using as the preimage for this file. | ||
| 528 | - | * This allows us to apply patches to files that have been | ||
| 529 | - | * modified in the working directory. During checkout, | ||
| 530 | - | * we will use this expected preimage as the baseline, and | ||
| 531 | - | * limit checkout to only the paths affected by patch | ||
| 532 | - | * application. (Without this, we would fail to write the | ||
| 533 | - | * postimage contents to any file that had been modified | ||
| 534 | - | * from HEAD on-disk, even if the patch application succeeded.) | ||
| 535 | - | * Use the contents from the delta where available - some | ||
| 536 | - | * fields may not be available, like the old file mode (eg in | ||
| 537 | - | * an exact rename situation) so trust the patch parsing to | ||
| 538 | - | * validate and use the preimage data in that case. | ||
| 539 | - | */ | ||
| 540 | 73 | 35 | if (preimage) { | |
| 541 | 73 | 36 | memset(&pre_entry, 0, sizeof(git_index_entry)); | |
| 542 | 73 | 36 | pre_entry.path = delta->old_file.path; | |
| 543 | 73 | 36-38 | pre_entry.mode = delta->old_file.mode ? delta->old_file.mode : pre_filemode; | |
| 544 | 73 | 39 | git_oid_cpy(&pre_entry.id, &pre_id); | |
| 545 | - | |||
| 546 | 73 | 40,41 | if ((error = git_index_add(preimage, &pre_entry)) < 0) | |
| 547 | ##### | 42 | goto done; | |
| 548 | - | } | ||
| 549 | - | } | ||
| 550 | - | |||
| 551 | 85 | 43 | if (delta->status != GIT_DELTA_DELETED) { | |
| 552 | 79 | 44,44,45 | if ((error = git_apply__patch(&post_contents, &filename, &mode, | |
| 553 | 79 | 44,46,47 | pre_contents.ptr, pre_contents.size, patch, opts)) < 0 || | |
| 554 | 76 | 46 | (error = git_blob_create_from_buffer(&post_id, repo, | |
| 555 | 76 | 46 | post_contents.ptr, post_contents.size)) < 0) | |
| 556 | - | goto done; | ||
| 557 | - | |||
| 558 | 76 | 48 | memset(&post_entry, 0, sizeof(git_index_entry)); | |
| 559 | 76 | 48 | post_entry.path = filename; | |
| 560 | 76 | 48 | post_entry.mode = mode; | |
| 561 | 76 | 48 | git_oid_cpy(&post_entry.id, &post_id); | |
| 562 | - | |||
| 563 | 76 | 49,50 | if ((error = git_index_add(postimage, &post_entry)) < 0) | |
| 564 | ##### | 51 | goto done; | |
| 565 | - | } | ||
| 566 | - | |||
| 567 | 82 | 52,53 | if (delta->status == GIT_DELTA_RENAMED || | |
| 568 | 69 | 53 | delta->status == GIT_DELTA_DELETED) | |
| 569 | 19 | 54 | error = git_strmap_set(removed_paths, delta->old_file.path, (char *) delta->old_file.path); | |
| 570 | - | |||
| 571 | 82 | 55,56 | if (delta->status == GIT_DELTA_RENAMED || | |
| 572 | 69 | 56 | delta->status == GIT_DELTA_ADDED) | |
| 573 | 20 | 57 | git_strmap_delete(removed_paths, delta->new_file.path); | |
| 574 | - | |||
| 575 | - | done: | ||
| 576 | 94 | 58 | git_buf_dispose(&pre_contents); | |
| 577 | 94 | 59 | git_buf_dispose(&post_contents); | |
| 578 | 94 | 60 | git__free(filename); | |
| 579 | 94 | 61 | git_patch_free(patch); | |
| 580 | - | |||
| 581 | 94 | 62 | return error; | |
| 582 | - | } | ||
| 583 | - | |||
| 584 | ![]() |
55 | 2 | static int apply_deltas( |
| 585 | - | git_repository *repo, | ||
| 586 | - | git_reader *pre_reader, | ||
| 587 | - | git_index *preimage, | ||
| 588 | - | git_reader *post_reader, | ||
| 589 | - | git_index *postimage, | ||
| 590 | - | git_diff *diff, | ||
| 591 | - | const git_apply_options *opts) | ||
| 592 | - | { | ||
| 593 | - | git_strmap *removed_paths; | ||
| 594 | - | size_t i; | ||
| 595 | 55 | 2 | int error = 0; | |
| 596 | - | |||
| 597 | 55 | 2,3 | if (git_strmap_new(&removed_paths) < 0) | |
| 598 | ##### | 4 | return -1; | |
| 599 | - | |||
| 600 | 138 | 5,9-11 | for (i = 0; i < git_diff_num_deltas(diff); i++) { | |
| 601 | 94 | 6,7 | if ((error = apply_one(repo, pre_reader, preimage, post_reader, postimage, diff, removed_paths, i, opts)) < 0) | |
| 602 | 11 | 8 | goto done; | |
| 603 | - | } | ||
| 604 | - | |||
| 605 | - | done: | ||
| 606 | 55 | 12 | git_strmap_free(removed_paths); | |
| 607 | 55 | 13 | return error; | |
| 608 | - | } | ||
| 609 | - | |||
| 610 | ![]() |
2 | 2 | int git_apply_to_tree( |
| 611 | - | git_index **out, | ||
| 612 | - | git_repository *repo, | ||
| 613 | - | git_tree *preimage, | ||
| 614 | - | git_diff *diff, | ||
| 615 | - | const git_apply_options *given_opts) | ||
| 616 | - | { | ||
| 617 | 2 | 2 | git_index *postimage = NULL; | |
| 618 | 2 | 2 | git_reader *pre_reader = NULL, *post_reader = NULL; | |
| 619 | 2 | 2 | git_apply_options opts = GIT_APPLY_OPTIONS_INIT; | |
| 620 | - | const git_diff_delta *delta; | ||
| 621 | - | size_t i; | ||
| 622 | 2 | 2 | int error = 0; | |
| 623 | - | |||
| 624 | 2 | 2-6 | assert(out && repo && preimage && diff); | |
| 625 | - | |||
| 626 | 2 | 7 | *out = NULL; | |
| 627 | - | |||
| 628 | 2 | 7 | if (given_opts) | |
| 629 | ##### | 8 | memcpy(&opts, given_opts, sizeof(git_apply_options)); | |
| 630 | - | |||
| 631 | 2 | 9,10 | if ((error = git_reader_for_tree(&pre_reader, preimage)) < 0) | |
| 632 | ##### | 11 | goto done; | |
| 633 | - | |||
| 634 | - | /* | ||
| 635 | - | * put the current tree into the postimage as-is - the diff will | ||
| 636 | - | * replace any entries contained therein | ||
| 637 | - | */ | ||
| 638 | 2 | 12-15 | if ((error = git_index_new(&postimage)) < 0 || | |
| 639 | 2 | 14,16,17 | (error = git_index_read_tree(postimage, preimage)) < 0 || | |
| 640 | 2 | 16 | (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) | |
| 641 | - | goto done; | ||
| 642 | - | |||
| 643 | - | /* | ||
| 644 | - | * Remove the old paths from the index before applying diffs - | ||
| 645 | - | * we need to do a full pass to remove them before adding deltas, | ||
| 646 | - | * in order to handle rename situations. | ||
| 647 | - | */ | ||
| 648 | 5 | 18,25-27 | for (i = 0; i < git_diff_num_deltas(diff); i++) { | |
| 649 | 3 | 19 | delta = git_diff_get_delta(diff, i); | |
| 650 | - | |||
| 651 | 3 | 20,21 | if (delta->status == GIT_DELTA_DELETED || | |
| 652 | 3 | 21 | delta->status == GIT_DELTA_RENAMED) { | |
| 653 | ##### | 22,23 | if ((error = git_index_remove(postimage, | |
| 654 | - | delta->old_file.path, 0)) < 0) | ||
| 655 | ##### | 24 | goto done; | |
| 656 | - | } | ||
| 657 | - | } | ||
| 658 | - | |||
| 659 | 2 | 28,29 | if ((error = apply_deltas(repo, pre_reader, NULL, post_reader, postimage, diff, &opts)) < 0) | |
| 660 | ##### | 30 | goto done; | |
| 661 | - | |||
| 662 | 2 | 31 | *out = postimage; | |
| 663 | - | |||
| 664 | - | done: | ||
| 665 | 2 | 32 | if (error < 0) | |
| 666 | ##### | 33 | git_index_free(postimage); | |
| 667 | - | |||
| 668 | 2 | 34 | git_reader_free(pre_reader); | |
| 669 | 2 | 35 | git_reader_free(post_reader); | |
| 670 | - | |||
| 671 | 2 | 36 | return error; | |
| 672 | - | } | ||
| 673 | - | |||
| 674 | ![]() |
31 | 2 | static int git_apply__to_workdir( |
| 675 | - | git_repository *repo, | ||
| 676 | - | git_diff *diff, | ||
| 677 | - | git_index *preimage, | ||
| 678 | - | git_index *postimage, | ||
| 679 | - | git_apply_location_t location, | ||
| 680 | - | git_apply_options *opts) | ||
| 681 | - | { | ||
| 682 | 31 | 2 | git_vector paths = GIT_VECTOR_INIT; | |
| 683 | 31 | 2 | git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; | |
| 684 | - | const git_diff_delta *delta; | ||
| 685 | - | size_t i; | ||
| 686 | - | int error; | ||
| 687 | - | |||
| 688 | - | GIT_UNUSED(opts); | ||
| 689 | - | |||
| 690 | - | /* | ||
| 691 | - | * Limit checkout to the paths affected by the diff; this ensures | ||
| 692 | - | * that other modifications in the working directory are unaffected. | ||
| 693 | - | */ | ||
| 694 | 31 | 2-4 | if ((error = git_vector_init(&paths, git_diff_num_deltas(diff), NULL)) < 0) | |
| 695 | ##### | 5 | goto done; | |
| 696 | - | |||
| 697 | 84 | 6,15-17 | for (i = 0; i < git_diff_num_deltas(diff); i++) { | |
| 698 | 53 | 7 | delta = git_diff_get_delta(diff, i); | |
| 699 | - | |||
| 700 | 53 | 8,9 | if ((error = git_vector_insert(&paths, (void *)delta->old_file.path)) < 0) | |
| 701 | ##### | 10 | goto done; | |
| 702 | - | |||
| 703 | 53 | 11-13 | if (strcmp(delta->old_file.path, delta->new_file.path) && | |
| 704 | 12 | 12 | (error = git_vector_insert(&paths, (void *)delta->new_file.path)) < 0) | |
| 705 | ##### | 14 | goto done; | |
| 706 | - | } | ||
| 707 | - | |||
| 708 | 31 | 18 | checkout_opts.checkout_strategy |= GIT_CHECKOUT_SAFE; | |
| 709 | 31 | 18 | checkout_opts.checkout_strategy |= GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; | |
| 710 | 31 | 18 | checkout_opts.checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX; | |
| 711 | - | |||
| 712 | 31 | 18 | if (location == GIT_APPLY_LOCATION_WORKDIR) | |
| 713 | 12 | 19 | checkout_opts.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX; | |
| 714 | - | |||
| 715 | 31 | 20 | checkout_opts.paths.strings = (char **)paths.contents; | |
| 716 | 31 | 20 | checkout_opts.paths.count = paths.length; | |
| 717 | - | |||
| 718 | 31 | 20 | checkout_opts.baseline_index = preimage; | |
| 719 | - | |||
| 720 | 31 | 20 | error = git_checkout_index(repo, postimage, &checkout_opts); | |
| 721 | - | |||
| 722 | - | done: | ||
| 723 | 31 | 21 | git_vector_free(&paths); | |
| 724 | 31 | 22 | return error; | |
| 725 | - | } | ||
| 726 | - | |||
| 727 | ![]() |
8 | 2 | static int git_apply__to_index( |
| 728 | - | git_repository *repo, | ||
| 729 | - | git_diff *diff, | ||
| 730 | - | git_index *preimage, | ||
| 731 | - | git_index *postimage, | ||
| 732 | - | git_apply_options *opts) | ||
| 733 | - | { | ||
| 734 | 8 | 2 | git_index *index = NULL; | |
| 735 | - | const git_diff_delta *delta; | ||
| 736 | - | const git_index_entry *entry; | ||
| 737 | - | size_t i; | ||
| 738 | - | int error; | ||
| 739 | - | |||
| 740 | - | GIT_UNUSED(preimage); | ||
| 741 | - | GIT_UNUSED(opts); | ||
| 742 | - | |||
| 743 | 8 | 2,3 | if ((error = git_repository_index(&index, repo)) < 0) | |
| 744 | ##### | 4 | goto done; | |
| 745 | - | |||
| 746 | - | /* Remove deleted (or renamed) paths from the index. */ | ||
| 747 | 21 | 5,12-14 | for (i = 0; i < git_diff_num_deltas(diff); i++) { | |
| 748 | 13 | 6 | delta = git_diff_get_delta(diff, i); | |
| 749 | - | |||
| 750 | 13 | 7,8 | if (delta->status == GIT_DELTA_DELETED || | |
| 751 | 12 | 8 | delta->status == GIT_DELTA_RENAMED) { | |
| 752 | 1 | 9,10 | if ((error = git_index_remove(index, delta->old_file.path, 0)) < 0) | |
| 753 | ##### | 11 | goto done; | |
| 754 | - | } | ||
| 755 | - | } | ||
| 756 | - | |||
| 757 | - | /* Then add the changes back to the index. */ | ||
| 758 | 20 | 15,20-22 | for (i = 0; i < git_index_entrycount(postimage); i++) { | |
| 759 | 12 | 16 | entry = git_index_get_byindex(postimage, i); | |
| 760 | - | |||
| 761 | 12 | 17,18 | if ((error = git_index_add(index, entry)) < 0) | |
| 762 | ##### | 19 | goto done; | |
| 763 | - | } | ||
| 764 | - | |||
| 765 | - | done: | ||
| 766 | 8 | 23 | git_index_free(index); | |
| 767 | 8 | 24 | return error; | |
| 768 | - | } | ||
| 769 | - | |||
| 770 | ![]() |
1 | 2 | int git_apply_options_init(git_apply_options *opts, unsigned int version) |
| 771 | - | { | ||
| 772 | 1 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
| 773 | - | opts, version, git_apply_options, GIT_APPLY_OPTIONS_INIT); | ||
| 774 | 1 | 5 | return 0; | |
| 775 | - | } | ||
| 776 | - | |||
| 777 | - | /* | ||
| 778 | - | * Handle the three application options ("locations"): | ||
| 779 | - | * | ||
| 780 | - | * GIT_APPLY_LOCATION_WORKDIR: the default, emulates `git apply`. | ||
| 781 | - | * Applies the diff only to the workdir items and ignores the index | ||
| 782 | - | * entirely. | ||
| 783 | - | * | ||
| 784 | - | * GIT_APPLY_LOCATION_INDEX: emulates `git apply --cached`. | ||
| 785 | - | * Applies the diff only to the index items and ignores the workdir | ||
| 786 | - | * completely. | ||
| 787 | - | * | ||
| 788 | - | * GIT_APPLY_LOCATION_BOTH: emulates `git apply --index`. | ||
| 789 | - | * Applies the diff to both the index items and the working directory | ||
| 790 | - | * items. | ||
| 791 | - | */ | ||
| 792 | - | |||
| 793 | ![]() |
53 | 2 | int git_apply( |
| 794 | - | git_repository *repo, | ||
| 795 | - | git_diff *diff, | ||
| 796 | - | git_apply_location_t location, | ||
| 797 | - | const git_apply_options *given_opts) | ||
| 798 | - | { | ||
| 799 | 53 | 2 | git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; | |
| 800 | 53 | 2 | git_index *index = NULL, *preimage = NULL, *postimage = NULL; | |
| 801 | 53 | 2 | git_reader *pre_reader = NULL, *post_reader = NULL; | |
| 802 | 53 | 2 | git_apply_options opts = GIT_APPLY_OPTIONS_INIT; | |
| 803 | 53 | 2 | int error = GIT_EINVALID; | |
| 804 | - | |||
| 805 | 53 | 2-4 | assert(repo && diff); | |
| 806 | - | |||
| 807 | 53 | 5-7 | GIT_ERROR_CHECK_VERSION( | |
| 808 | - | given_opts, GIT_APPLY_OPTIONS_VERSION, "git_apply_options"); | ||
| 809 | - | |||
| 810 | 53 | 8 | if (given_opts) | |
| 811 | 9 | 9 | memcpy(&opts, given_opts, sizeof(git_apply_options)); | |
| 812 | - | |||
| 813 | - | /* | ||
| 814 | - | * by default, we apply a patch directly to the working directory; | ||
| 815 | - | * in `--cached` or `--index` mode, we apply to the contents already | ||
| 816 | - | * in the index. | ||
| 817 | - | */ | ||
| 818 | 53 | 10 | switch (location) { | |
| 819 | - | case GIT_APPLY_LOCATION_BOTH: | ||
| 820 | 27 | 11 | error = git_reader_for_workdir(&pre_reader, repo, true); | |
| 821 | 27 | 17 | break; | |
| 822 | - | case GIT_APPLY_LOCATION_INDEX: | ||
| 823 | 13 | 12 | error = git_reader_for_index(&pre_reader, repo, NULL); | |
| 824 | 13 | 13 | break; | |
| 825 | - | case GIT_APPLY_LOCATION_WORKDIR: | ||
| 826 | 13 | 14 | error = git_reader_for_workdir(&pre_reader, repo, false); | |
| 827 | 13 | 15 | break; | |
| 828 | - | default: | ||
| 829 | - | 16 | assert(false); | |
| 830 | - | } | ||
| 831 | - | |||
| 832 | 53 | 18 | if (error < 0) | |
| 833 | ##### | 19 | goto done; | |
| 834 | - | |||
| 835 | - | /* | ||
| 836 | - | * Build the preimage and postimage (differences). Note that | ||
| 837 | - | * this is not the complete preimage or postimage, it only | ||
| 838 | - | * contains the files affected by the patch. We want to avoid | ||
| 839 | - | * having the full repo index, so we will limit our checkout | ||
| 840 | - | * to only write these files that were affected by the diff. | ||
| 841 | - | */ | ||
| 842 | 53 | 20-23 | if ((error = git_index_new(&preimage)) < 0 || | |
| 843 | 53 | 24,25 | (error = git_index_new(&postimage)) < 0 || | |
| 844 | 53 | 24 | (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) | |
| 845 | - | goto done; | ||
| 846 | - | |||
| 847 | 53 | 26 | if (!(opts.flags & GIT_APPLY_CHECK)) | |
| 848 | 49 | 27-30 | if ((error = git_repository_index(&index, repo)) < 0 || | |
| 849 | 49 | 29 | (error = git_indexwriter_init(&indexwriter, index)) < 0) | |
| 850 | - | goto done; | ||
| 851 | - | |||
| 852 | 53 | 31,32 | if ((error = apply_deltas(repo, pre_reader, preimage, post_reader, postimage, diff, &opts)) < 0) | |
| 853 | 11 | 33 | goto done; | |
| 854 | - | |||
| 855 | 42 | 34 | if ((opts.flags & GIT_APPLY_CHECK)) | |
| 856 | 3 | 35 | goto done; | |
| 857 | - | |||
| 858 | 39 | 36 | switch (location) { | |
| 859 | - | case GIT_APPLY_LOCATION_BOTH: | ||
| 860 | 19 | 37 | error = git_apply__to_workdir(repo, diff, preimage, postimage, location, &opts); | |
| 861 | 19 | 43 | break; | |
| 862 | - | case GIT_APPLY_LOCATION_INDEX: | ||
| 863 | 8 | 38 | error = git_apply__to_index(repo, diff, preimage, postimage, &opts); | |
| 864 | 8 | 39 | break; | |
| 865 | - | case GIT_APPLY_LOCATION_WORKDIR: | ||
| 866 | 12 | 40 | error = git_apply__to_workdir(repo, diff, preimage, postimage, location, &opts); | |
| 867 | 12 | 41 | break; | |
| 868 | - | default: | ||
| 869 | - | 42 | assert(false); | |
| 870 | - | } | ||
| 871 | - | |||
| 872 | 39 | 44 | if (error < 0) | |
| 873 | ##### | 45 | goto done; | |
| 874 | - | |||
| 875 | 39 | 46 | error = git_indexwriter_commit(&indexwriter); | |
| 876 | - | |||
| 877 | - | done: | ||
| 878 | 53 | 47 | git_indexwriter_cleanup(&indexwriter); | |
| 879 | 53 | 48 | git_index_free(postimage); | |
| 880 | 53 | 49 | git_index_free(preimage); | |
| 881 | 53 | 50 | git_index_free(index); | |
| 882 | 53 | 51 | git_reader_free(pre_reader); | |
| 883 | 53 | 52 | git_reader_free(post_reader); | |
| 884 | - | |||
| 885 | 53 | 53 | return error; | |
| 886 | - | } |