rugged 0.25.0b10 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/extconf.rb +5 -0
  3. data/ext/rugged/rugged.c +3 -20
  4. data/ext/rugged/rugged.h +3 -20
  5. data/ext/rugged/rugged_backend.c +3 -20
  6. data/ext/rugged/rugged_blame.c +7 -24
  7. data/ext/rugged/rugged_blob.c +5 -22
  8. data/ext/rugged/rugged_branch.c +3 -20
  9. data/ext/rugged/rugged_branch_collection.c +3 -20
  10. data/ext/rugged/rugged_commit.c +37 -24
  11. data/ext/rugged/rugged_config.c +3 -20
  12. data/ext/rugged/rugged_cred.c +3 -20
  13. data/ext/rugged/rugged_diff.c +3 -20
  14. data/ext/rugged/rugged_diff_delta.c +3 -20
  15. data/ext/rugged/rugged_diff_hunk.c +3 -20
  16. data/ext/rugged/rugged_diff_line.c +3 -20
  17. data/ext/rugged/rugged_index.c +38 -149
  18. data/ext/rugged/rugged_note.c +3 -20
  19. data/ext/rugged/rugged_object.c +3 -20
  20. data/ext/rugged/rugged_patch.c +4 -22
  21. data/ext/rugged/rugged_rebase.c +3 -20
  22. data/ext/rugged/rugged_reference.c +4 -21
  23. data/ext/rugged/rugged_reference_collection.c +3 -20
  24. data/ext/rugged/rugged_remote.c +4 -21
  25. data/ext/rugged/rugged_remote_collection.c +3 -20
  26. data/ext/rugged/rugged_repo.c +5 -22
  27. data/ext/rugged/rugged_revwalk.c +4 -21
  28. data/ext/rugged/rugged_settings.c +3 -20
  29. data/ext/rugged/rugged_signature.c +3 -20
  30. data/ext/rugged/rugged_submodule.c +4 -21
  31. data/ext/rugged/rugged_submodule_collection.c +3 -20
  32. data/ext/rugged/rugged_tag.c +3 -20
  33. data/ext/rugged/rugged_tag_collection.c +3 -20
  34. data/ext/rugged/rugged_tree.c +56 -183
  35. data/lib/rugged.rb +5 -0
  36. data/lib/rugged/attributes.rb +5 -0
  37. data/lib/rugged/blob.rb +5 -0
  38. data/lib/rugged/branch.rb +6 -1
  39. data/lib/rugged/commit.rb +5 -0
  40. data/lib/rugged/console.rb +5 -0
  41. data/lib/rugged/credentials.rb +5 -0
  42. data/lib/rugged/diff.rb +5 -0
  43. data/lib/rugged/diff/delta.rb +5 -0
  44. data/lib/rugged/diff/hunk.rb +5 -0
  45. data/lib/rugged/diff/line.rb +5 -0
  46. data/lib/rugged/index.rb +120 -0
  47. data/lib/rugged/object.rb +5 -0
  48. data/lib/rugged/patch.rb +5 -0
  49. data/lib/rugged/reference.rb +5 -0
  50. data/lib/rugged/remote.rb +5 -0
  51. data/lib/rugged/repository.rb +6 -1
  52. data/lib/rugged/submodule_collection.rb +5 -0
  53. data/lib/rugged/tag.rb +5 -0
  54. data/lib/rugged/tree.rb +156 -1
  55. data/lib/rugged/version.rb +6 -1
  56. data/lib/rugged/walker.rb +5 -0
  57. data/vendor/libgit2/include/git2/common.h +20 -1
  58. data/vendor/libgit2/include/git2/describe.h +5 -2
  59. data/vendor/libgit2/include/git2/patch.h +1 -1
  60. data/vendor/libgit2/include/git2/proxy.h +1 -1
  61. data/vendor/libgit2/include/git2/remote.h +4 -4
  62. data/vendor/libgit2/include/git2/transaction.h +9 -0
  63. data/vendor/libgit2/include/git2/version.h +3 -3
  64. data/vendor/libgit2/src/apply.c +1 -1
  65. data/vendor/libgit2/src/branch.c +5 -4
  66. data/vendor/libgit2/src/checkout.c +2 -2
  67. data/vendor/libgit2/src/commit.c +4 -3
  68. data/vendor/libgit2/src/common.h +2 -1
  69. data/vendor/libgit2/src/curl_stream.c +19 -2
  70. data/vendor/libgit2/src/diff_stats.c +18 -10
  71. data/vendor/libgit2/src/fetchhead.c +8 -8
  72. data/vendor/libgit2/src/fileops.c +9 -1
  73. data/vendor/libgit2/src/fileops.h +2 -2
  74. data/vendor/libgit2/src/global.c +19 -4
  75. data/vendor/libgit2/src/global.h +6 -0
  76. data/vendor/libgit2/src/graph.c +1 -1
  77. data/vendor/libgit2/src/index.c +1 -1
  78. data/vendor/libgit2/src/iterator.c +1 -1
  79. data/vendor/libgit2/src/merge.c +1 -1
  80. data/vendor/libgit2/src/odb.c +1 -1
  81. data/vendor/libgit2/src/odb_mempack.c +1 -1
  82. data/vendor/libgit2/src/openssl_stream.c +45 -26
  83. data/vendor/libgit2/src/openssl_stream.h +106 -0
  84. data/vendor/libgit2/src/pack.c +12 -7
  85. data/vendor/libgit2/src/patch_generate.c +1 -1
  86. data/vendor/libgit2/src/patch_parse.c +28 -26
  87. data/vendor/libgit2/src/path.c +5 -2
  88. data/vendor/libgit2/src/pqueue.c +3 -2
  89. data/vendor/libgit2/src/rebase.c +1 -1
  90. data/vendor/libgit2/src/refdb.c +4 -2
  91. data/vendor/libgit2/src/refdb_fs.c +82 -54
  92. data/vendor/libgit2/src/repository.c +9 -6
  93. data/vendor/libgit2/src/revwalk.c +1 -1
  94. data/vendor/libgit2/src/settings.c +2 -0
  95. data/vendor/libgit2/src/signature.c +1 -1
  96. data/vendor/libgit2/src/sortedcache.c +14 -5
  97. data/vendor/libgit2/src/sysdir.c +1 -1
  98. data/vendor/libgit2/src/transports/http.c +1 -1
  99. data/vendor/libgit2/src/transports/smart_protocol.c +11 -7
  100. data/vendor/libgit2/src/tree.c +13 -5
  101. data/vendor/libgit2/src/unix/pthread.h +2 -0
  102. data/vendor/libgit2/src/win32/thread.c +18 -0
  103. data/vendor/libgit2/src/win32/thread.h +2 -0
  104. data/vendor/libgit2/src/win32/w32_util.h +1 -1
  105. data/vendor/libgit2/src/zstream.c +1 -1
  106. metadata +76 -76
@@ -284,7 +284,7 @@ static int create_binary(
284
284
  size_t b_datalen)
285
285
  {
286
286
  git_buf deflate = GIT_BUF_INIT, delta = GIT_BUF_INIT;
287
- size_t delta_data_len;
287
+ size_t delta_data_len = 0;
288
288
  int error;
289
289
 
290
290
  /* The git_delta function accepts unsigned long only */
@@ -176,7 +176,7 @@ static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx)
176
176
  int ret;
177
177
 
178
178
  if (ctx->line_len < 1 || !git__isdigit(ctx->line[0]))
179
- return parse_err("invalid file mode at line %d", ctx->line_num);
179
+ return parse_err("invalid file mode at line %"PRIuZ, ctx->line_num);
180
180
 
181
181
  if ((ret = git__strntol32(&m, ctx->line, ctx->line_len, &end, 8)) < 0)
182
182
  return ret;
@@ -205,7 +205,7 @@ static int parse_header_oid(
205
205
 
206
206
  if (len < GIT_OID_MINPREFIXLEN || len > GIT_OID_HEXSZ ||
207
207
  git_oid_fromstrn(oid, ctx->line, len) < 0)
208
- return parse_err("invalid hex formatted object id at line %d",
208
+ return parse_err("invalid hex formatted object id at line %"PRIuZ,
209
209
  ctx->line_num);
210
210
 
211
211
  parse_advance_chars(ctx, len);
@@ -350,7 +350,7 @@ static int parse_header_similarity(
350
350
  git_patch_parsed *patch, git_patch_parse_ctx *ctx)
351
351
  {
352
352
  if (parse_header_percent(&patch->base.delta->similarity, ctx) < 0)
353
- return parse_err("invalid similarity percentage at line %d",
353
+ return parse_err("invalid similarity percentage at line %"PRIuZ,
354
354
  ctx->line_num);
355
355
 
356
356
  return 0;
@@ -362,7 +362,7 @@ static int parse_header_dissimilarity(
362
362
  uint16_t dissimilarity;
363
363
 
364
364
  if (parse_header_percent(&dissimilarity, ctx) < 0)
365
- return parse_err("invalid similarity percentage at line %d",
365
+ return parse_err("invalid similarity percentage at line %"PRIuZ,
366
366
  ctx->line_num);
367
367
 
368
368
  patch->base.delta->similarity = 100 - dissimilarity;
@@ -406,15 +406,15 @@ static int parse_header_git(
406
406
 
407
407
  /* Parse the diff --git line */
408
408
  if (parse_advance_expected_str(ctx, "diff --git ") < 0)
409
- return parse_err("corrupt git diff header at line %d", ctx->line_num);
409
+ return parse_err("corrupt git diff header at line %"PRIuZ, ctx->line_num);
410
410
 
411
411
  if (parse_header_path(&patch->header_old_path, ctx) < 0)
412
- return parse_err("corrupt old path in git diff header at line %d",
412
+ return parse_err("corrupt old path in git diff header at line %"PRIuZ,
413
413
  ctx->line_num);
414
414
 
415
415
  if (parse_advance_ws(ctx) < 0 ||
416
416
  parse_header_path(&patch->header_new_path, ctx) < 0)
417
- return parse_err("corrupt new path in git diff header at line %d",
417
+ return parse_err("corrupt new path in git diff header at line %"PRIuZ,
418
418
  ctx->line_num);
419
419
 
420
420
  /* Parse remaining header lines */
@@ -447,7 +447,7 @@ static int parse_header_git(
447
447
  parse_advance_expected_str(ctx, "\n");
448
448
 
449
449
  if (ctx->line_len > 0) {
450
- error = parse_err("trailing data at line %d", ctx->line_num);
450
+ error = parse_err("trailing data at line %"PRIuZ, ctx->line_num);
451
451
  goto done;
452
452
  }
453
453
 
@@ -456,7 +456,7 @@ static int parse_header_git(
456
456
  }
457
457
 
458
458
  if (!found) {
459
- error = parse_err("invalid patch header at line %d",
459
+ error = parse_err("invalid patch header at line %"PRIuZ,
460
460
  ctx->line_num);
461
461
  goto done;
462
462
  }
@@ -536,7 +536,7 @@ static int parse_hunk_header(
536
536
 
537
537
  hunk->hunk.header_len = ctx->line - header_start;
538
538
  if (hunk->hunk.header_len > (GIT_DIFF_HUNK_HEADER_SIZE - 1))
539
- return parse_err("oversized patch hunk header at line %d",
539
+ return parse_err("oversized patch hunk header at line %"PRIuZ,
540
540
  ctx->line_num);
541
541
 
542
542
  memcpy(hunk->hunk.header, header_start, hunk->hunk.header_len);
@@ -545,7 +545,7 @@ static int parse_hunk_header(
545
545
  return 0;
546
546
 
547
547
  fail:
548
- giterr_set(GITERR_PATCH, "invalid patch hunk header at line %d",
548
+ giterr_set(GITERR_PATCH, "invalid patch hunk header at line %"PRIuZ,
549
549
  ctx->line_num);
550
550
  return -1;
551
551
  }
@@ -570,7 +570,7 @@ static int parse_hunk_body(
570
570
  int prefix = 1;
571
571
 
572
572
  if (ctx->line_len == 0 || ctx->line[ctx->line_len - 1] != '\n') {
573
- error = parse_err("invalid patch instruction at line %d",
573
+ error = parse_err("invalid patch instruction at line %"PRIuZ,
574
574
  ctx->line_num);
575
575
  goto done;
576
576
  }
@@ -596,7 +596,7 @@ static int parse_hunk_body(
596
596
  break;
597
597
 
598
598
  default:
599
- error = parse_err("invalid patch hunk at line %d", ctx->line_num);
599
+ error = parse_err("invalid patch hunk at line %"PRIuZ, ctx->line_num);
600
600
  goto done;
601
601
  }
602
602
 
@@ -672,7 +672,7 @@ static int parse_patch_header(
672
672
  continue;
673
673
  }
674
674
 
675
- error = parse_err("invalid hunk header outside patch at line %d",
675
+ error = parse_err("invalid hunk header outside patch at line %"PRIuZ,
676
676
  line_num);
677
677
  goto done;
678
678
  }
@@ -715,12 +715,12 @@ static int parse_patch_binary_side(
715
715
  parse_advance_chars(ctx, 6);
716
716
  } else {
717
717
  error = parse_err(
718
- "unknown binary delta type at line %d", ctx->line_num);
718
+ "unknown binary delta type at line %"PRIuZ, ctx->line_num);
719
719
  goto done;
720
720
  }
721
721
 
722
722
  if (parse_number(&len, ctx) < 0 || parse_advance_nl(ctx) < 0 || len < 0) {
723
- error = parse_err("invalid binary size at line %d", ctx->line_num);
723
+ error = parse_err("invalid binary size at line %"PRIuZ, ctx->line_num);
724
724
  goto done;
725
725
  }
726
726
 
@@ -736,7 +736,7 @@ static int parse_patch_binary_side(
736
736
  decoded_len = c - 'a' + (('z' - 'a') + 1) + 1;
737
737
 
738
738
  if (!decoded_len) {
739
- error = parse_err("invalid binary length at line %d", ctx->line_num);
739
+ error = parse_err("invalid binary length at line %"PRIuZ, ctx->line_num);
740
740
  goto done;
741
741
  }
742
742
 
@@ -745,7 +745,7 @@ static int parse_patch_binary_side(
745
745
  encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5;
746
746
 
747
747
  if (encoded_len > ctx->line_len - 1) {
748
- error = parse_err("truncated binary data at line %d", ctx->line_num);
748
+ error = parse_err("truncated binary data at line %"PRIuZ, ctx->line_num);
749
749
  goto done;
750
750
  }
751
751
 
@@ -754,14 +754,14 @@ static int parse_patch_binary_side(
754
754
  goto done;
755
755
 
756
756
  if (decoded.size - decoded_orig != decoded_len) {
757
- error = parse_err("truncated binary data at line %d", ctx->line_num);
757
+ error = parse_err("truncated binary data at line %"PRIuZ, ctx->line_num);
758
758
  goto done;
759
759
  }
760
760
 
761
761
  parse_advance_chars(ctx, encoded_len);
762
762
 
763
763
  if (parse_advance_nl(ctx) < 0) {
764
- error = parse_err("trailing data at line %d", ctx->line_num);
764
+ error = parse_err("trailing data at line %"PRIuZ, ctx->line_num);
765
765
  goto done;
766
766
  }
767
767
  }
@@ -785,7 +785,7 @@ static int parse_patch_binary(
785
785
 
786
786
  if (parse_advance_expected_str(ctx, "GIT binary patch") < 0 ||
787
787
  parse_advance_nl(ctx) < 0)
788
- return parse_err("corrupt git binary header at line %d", ctx->line_num);
788
+ return parse_err("corrupt git binary header at line %"PRIuZ, ctx->line_num);
789
789
 
790
790
  /* parse old->new binary diff */
791
791
  if ((error = parse_patch_binary_side(
@@ -793,7 +793,7 @@ static int parse_patch_binary(
793
793
  return error;
794
794
 
795
795
  if (parse_advance_nl(ctx) < 0)
796
- return parse_err("corrupt git binary separator at line %d",
796
+ return parse_err("corrupt git binary separator at line %"PRIuZ,
797
797
  ctx->line_num);
798
798
 
799
799
  /* parse new->old binary diff */
@@ -802,7 +802,7 @@ static int parse_patch_binary(
802
802
  return error;
803
803
 
804
804
  if (parse_advance_nl(ctx) < 0)
805
- return parse_err("corrupt git binary patch separator at line %d",
805
+ return parse_err("corrupt git binary patch separator at line %"PRIuZ,
806
806
  ctx->line_num);
807
807
 
808
808
  patch->base.binary.contains_data = 1;
@@ -820,7 +820,7 @@ static int parse_patch_binary_nodata(
820
820
  parse_advance_expected_str(ctx, patch->header_new_path) < 0 ||
821
821
  parse_advance_expected_str(ctx, " differ") < 0 ||
822
822
  parse_advance_nl(ctx) < 0)
823
- return parse_err("corrupt git binary header at line %d", ctx->line_num);
823
+ return parse_err("corrupt git binary header at line %"PRIuZ, ctx->line_num);
824
824
 
825
825
  patch->base.binary.contains_data = 0;
826
826
  patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
@@ -912,7 +912,7 @@ static int check_prefix(
912
912
 
913
913
  if (remain_len || !*path)
914
914
  return parse_err(
915
- "header filename does not contain %d path components",
915
+ "header filename does not contain %"PRIuZ" path components",
916
916
  prefix_len);
917
917
 
918
918
  done:
@@ -1014,8 +1014,10 @@ git_patch_parse_ctx *git_patch_parse_ctx_init(
1014
1014
  return NULL;
1015
1015
 
1016
1016
  if (content_len) {
1017
- if ((ctx->content = git__malloc(content_len)) == NULL)
1017
+ if ((ctx->content = git__malloc(content_len)) == NULL) {
1018
+ git__free(ctx);
1018
1019
  return NULL;
1020
+ }
1019
1021
 
1020
1022
  memcpy((char *)ctx->content, content, content_len);
1021
1023
  }
@@ -644,6 +644,10 @@ int git_path_set_error(int errno_value, const char *path, const char *action)
644
644
  giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path);
645
645
  return GIT_EEXISTS;
646
646
 
647
+ case EACCES:
648
+ giterr_set(GITERR_OS, "Failed %s - '%s' is locked", action, path);
649
+ return GIT_ELOCKED;
650
+
647
651
  default:
648
652
  giterr_set(GITERR_OS, "Could not %s '%s'", action, path);
649
653
  return -1;
@@ -1141,7 +1145,6 @@ int git_path_diriter_init(
1141
1145
  unsigned int flags)
1142
1146
  {
1143
1147
  git_win32_path path_filter;
1144
- git_buf hack = {0};
1145
1148
 
1146
1149
  static int is_win7_or_later = -1;
1147
1150
  if (is_win7_or_later < 0)
@@ -1347,7 +1350,7 @@ int git_path_diriter_next(git_path_diriter *diriter)
1347
1350
  return GIT_ITEROVER;
1348
1351
 
1349
1352
  giterr_set(GITERR_OS,
1350
- "Could not read directory '%s'", diriter->path);
1353
+ "Could not read directory '%s'", diriter->path.ptr);
1351
1354
  return -1;
1352
1355
  }
1353
1356
  } while (skip_dot && git_path_is_dot_or_dotdot(de->d_name));
@@ -86,8 +86,9 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
86
86
  if ((pq->flags & GIT_PQUEUE_FIXED_SIZE) != 0 &&
87
87
  pq->length >= pq->_alloc_size)
88
88
  {
89
- /* skip this item if below min item in heap */
90
- if (pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
89
+ /* skip this item if below min item in heap or if
90
+ * we do not have a comparison function */
91
+ if (!pq->_cmp || pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
91
92
  return 0;
92
93
  /* otherwise remove the min item before inserting new */
93
94
  (void)git_pqueue_pop(pq);
@@ -630,7 +630,7 @@ static int rebase_init_merge(
630
630
  rebase->state_path = git_buf_detach(&state_path);
631
631
  GITERR_CHECK_ALLOC(rebase->state_path);
632
632
 
633
- if (branch->ref_name) {
633
+ if (branch->ref_name && strcmp(branch->ref_name, "HEAD")) {
634
634
  rebase->orig_head_name = git__strdup(branch->ref_name);
635
635
  GITERR_CHECK_ALLOC(rebase->orig_head_name);
636
636
  } else {
@@ -125,13 +125,15 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
125
125
 
126
126
  int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
127
127
  {
128
+ int error;
129
+
128
130
  if (!db->backend || !db->backend->iterator) {
129
131
  giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
130
132
  return -1;
131
133
  }
132
134
 
133
- if (db->backend->iterator(out, db->backend, glob) < 0)
134
- return -1;
135
+ if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
136
+ return error;
135
137
 
136
138
  GIT_REFCOUNT_INC(db);
137
139
  (*out)->db = db;
@@ -326,12 +326,13 @@ static int refdb_fs_backend__exists(
326
326
  {
327
327
  refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
328
328
  git_buf ref_path = GIT_BUF_INIT;
329
+ int error;
329
330
 
330
331
  assert(backend);
331
332
 
332
- if (packed_reload(backend) < 0 ||
333
- git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
334
- return -1;
333
+ if ((error = packed_reload(backend)) < 0 ||
334
+ (error = git_buf_joinpath(&ref_path, backend->path, ref_name)) < 0)
335
+ return error;
335
336
 
336
337
  *exists = git_path_isfile(ref_path.ptr) ||
337
338
  (git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
@@ -409,8 +410,8 @@ static int packed_lookup(
409
410
  int error = 0;
410
411
  struct packref *entry;
411
412
 
412
- if (packed_reload(backend) < 0)
413
- return -1;
413
+ if ((error = packed_reload(backend)) < 0)
414
+ return error;
414
415
 
415
416
  if (git_sortedcache_rlock(backend->refcache) < 0)
416
417
  return -1;
@@ -615,13 +616,14 @@ static int refdb_fs_backend__iterator_next_name(
615
616
  static int refdb_fs_backend__iterator(
616
617
  git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
617
618
  {
619
+ int error;
618
620
  refdb_fs_iter *iter;
619
621
  refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
620
622
 
621
623
  assert(backend);
622
624
 
623
- if (packed_reload(backend) < 0)
624
- return -1;
625
+ if ((error = packed_reload(backend)) < 0)
626
+ return error;
625
627
 
626
628
  iter = git__calloc(1, sizeof(refdb_fs_iter));
627
629
  GITERR_CHECK_ALLOC(iter);
@@ -674,16 +676,18 @@ static int reference_path_available(
674
676
  int force)
675
677
  {
676
678
  size_t i;
679
+ int error;
677
680
 
678
- if (packed_reload(backend) < 0)
679
- return -1;
681
+ if ((error = packed_reload(backend)) < 0)
682
+ return error;
680
683
 
681
684
  if (!force) {
682
685
  int exists;
683
686
 
684
- if (refdb_fs_backend__exists(
685
- &exists, (git_refdb_backend *)backend, new_ref) < 0)
686
- return -1;
687
+ if ((error = refdb_fs_backend__exists(
688
+ &exists, (git_refdb_backend *)backend, new_ref)) < 0) {
689
+ return error;
690
+ }
687
691
 
688
692
  if (exists) {
689
693
  giterr_set(GITERR_REFERENCE,
@@ -725,8 +729,8 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
725
729
  /* Remove a possibly existing empty directory hierarchy
726
730
  * which name would collide with the reference name
727
731
  */
728
- if (git_futils_rmdir_r(name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0)
729
- return -1;
732
+ if ((error = git_futils_rmdir_r(name, backend->path, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
733
+ return error;
730
734
 
731
735
  if (git_buf_joinpath(&ref_path, backend->path, name) < 0)
732
736
  return -1;
@@ -901,40 +905,62 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file)
901
905
  static int packed_remove_loose(refdb_fs_backend *backend)
902
906
  {
903
907
  size_t i;
904
- git_buf full_path = GIT_BUF_INIT;
905
- int failed = 0;
908
+ git_filebuf lock = GIT_FILEBUF_INIT;
909
+ git_buf ref_content = GIT_BUF_INIT;
910
+ int error = 0;
906
911
 
907
912
  /* backend->refcache is already locked when this is called */
908
913
 
909
914
  for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
910
915
  struct packref *ref = git_sortedcache_entry(backend->refcache, i);
916
+ git_oid current_id;
911
917
 
912
918
  if (!ref || !(ref->flags & PACKREF_WAS_LOOSE))
913
919
  continue;
914
920
 
915
- if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0)
916
- return -1; /* critical; do not try to recover on oom */
921
+ git_filebuf_cleanup(&lock);
917
922
 
918
- if (git_path_exists(full_path.ptr) && p_unlink(full_path.ptr) < 0) {
919
- if (failed)
920
- continue;
923
+ /* We need to stop anybody from updating the ref while we try to do a safe delete */
924
+ error = loose_lock(&lock, backend, ref->name);
925
+ /* If someone else is updating it, let them do it */
926
+ if (error == GIT_EEXISTS || error == GIT_ENOTFOUND)
927
+ continue;
921
928
 
922
- giterr_set(GITERR_REFERENCE,
923
- "Failed to remove loose reference '%s' after packing: %s",
924
- full_path.ptr, strerror(errno));
925
- failed = 1;
929
+ if (error < 0) {
930
+ git_buf_free(&ref_content);
931
+ giterr_set(GITERR_REFERENCE, "failed to lock loose reference '%s'", ref->name);
932
+ return error;
926
933
  }
927
934
 
935
+ error = git_futils_readbuffer(&ref_content, lock.path_original);
936
+ /* Someone else beat us to cleaning up the ref, let's simply continue */
937
+ if (error == GIT_ENOTFOUND)
938
+ continue;
939
+
940
+ /* This became a symref between us packing and trying to delete it, so ignore it */
941
+ if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF))
942
+ continue;
943
+
944
+ /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
945
+ if (loose_parse_oid(&current_id, lock.path_original, &ref_content) < 0)
946
+ continue;
947
+
948
+ /* If the ref moved since we packed it, we must not delete it */
949
+ if (!git_oid_equal(&current_id, &ref->oid))
950
+ continue;
951
+
928
952
  /*
929
953
  * if we fail to remove a single file, this is *not* good,
930
954
  * but we should keep going and remove as many as possible.
931
- * After we've removed as many files as possible, we return
932
- * the error code anyway.
955
+ * If we fail to remove, the ref is still in the old state, so
956
+ * we haven't lost information.
933
957
  */
958
+ p_unlink(lock.path_original);
934
959
  }
935
960
 
936
- git_buf_free(&full_path);
937
- return failed ? -1 : 0;
961
+ git_buf_free(&ref_content);
962
+ git_filebuf_cleanup(&lock);
963
+ return 0;
938
964
  }
939
965
 
940
966
  /*
@@ -944,41 +970,42 @@ static int packed_write(refdb_fs_backend *backend)
944
970
  {
945
971
  git_sortedcache *refcache = backend->refcache;
946
972
  git_filebuf pack_file = GIT_FILEBUF_INIT;
973
+ int error;
947
974
  size_t i;
948
975
 
949
976
  /* lock the cache to updates while we do this */
950
- if (git_sortedcache_wlock(refcache) < 0)
951
- return -1;
977
+ if ((error = git_sortedcache_wlock(refcache)) < 0)
978
+ return error;
952
979
 
953
980
  /* Open the file! */
954
- if (git_filebuf_open(&pack_file, git_sortedcache_path(refcache), 0, GIT_PACKEDREFS_FILE_MODE) < 0)
981
+ if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), 0, GIT_PACKEDREFS_FILE_MODE)) < 0)
955
982
  goto fail;
956
983
 
957
984
  /* Packfiles have a header... apparently
958
985
  * This is in fact not required, but we might as well print it
959
986
  * just for kicks */
960
- if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0)
987
+ if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0)
961
988
  goto fail;
962
989
 
963
990
  for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) {
964
991
  struct packref *ref = git_sortedcache_entry(refcache, i);
965
992
  assert(ref);
966
993
 
967
- if (packed_find_peel(backend, ref) < 0)
994
+ if ((error = packed_find_peel(backend, ref)) < 0)
968
995
  goto fail;
969
996
 
970
- if (packed_write_ref(ref, &pack_file) < 0)
997
+ if ((error = packed_write_ref(ref, &pack_file)) < 0)
971
998
  goto fail;
972
999
  }
973
1000
 
974
1001
  /* if we've written all the references properly, we can commit
975
1002
  * the packfile to make the changes effective */
976
- if (git_filebuf_commit(&pack_file) < 0)
1003
+ if ((error = git_filebuf_commit(&pack_file)) < 0)
977
1004
  goto fail;
978
1005
 
979
1006
  /* when and only when the packfile has been properly written,
980
1007
  * we can go ahead and remove the loose refs */
981
- if (packed_remove_loose(backend) < 0)
1008
+ if ((error = packed_remove_loose(backend)) < 0)
982
1009
  goto fail;
983
1010
 
984
1011
  git_sortedcache_updated(refcache);
@@ -991,7 +1018,7 @@ fail:
991
1018
  git_filebuf_cleanup(&pack_file);
992
1019
  git_sortedcache_wunlock(refcache);
993
1020
 
994
- return -1;
1021
+ return error;
995
1022
  }
996
1023
 
997
1024
  static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
@@ -1143,8 +1170,7 @@ static int refdb_fs_backend__write(
1143
1170
 
1144
1171
  assert(backend);
1145
1172
 
1146
- error = reference_path_available(backend, ref->name, NULL, force);
1147
- if (error < 0)
1173
+ if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
1148
1174
  return error;
1149
1175
 
1150
1176
  /* We need to perform the reflog append and old value check under the ref's lock */
@@ -1260,15 +1286,14 @@ static int refdb_fs_backend__delete_tail(
1260
1286
  if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0)
1261
1287
  return -1;
1262
1288
 
1263
- if (git_path_isfile(loose_path.ptr)) {
1264
- error = p_unlink(loose_path.ptr);
1265
- loose_deleted = 1;
1266
- }
1267
-
1268
- git_buf_free(&loose_path);
1269
1289
 
1270
- if (error != 0)
1290
+ error = p_unlink(loose_path.ptr);
1291
+ if (error < 0 && errno == ENOENT)
1292
+ error = 0;
1293
+ else if (error < 0)
1271
1294
  goto cleanup;
1295
+ else if (error == 0)
1296
+ loose_deleted = 1;
1272
1297
 
1273
1298
  if ((error = packed_reload(backend)) < 0)
1274
1299
  goto cleanup;
@@ -1291,6 +1316,7 @@ static int refdb_fs_backend__delete_tail(
1291
1316
  error = packed_write(backend);
1292
1317
 
1293
1318
  cleanup:
1319
+ git_buf_free(&loose_path);
1294
1320
  git_filebuf_cleanup(file);
1295
1321
 
1296
1322
  return error;
@@ -1362,14 +1388,15 @@ static int refdb_fs_backend__rename(
1362
1388
 
1363
1389
  static int refdb_fs_backend__compress(git_refdb_backend *_backend)
1364
1390
  {
1391
+ int error;
1365
1392
  refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
1366
1393
 
1367
1394
  assert(backend);
1368
1395
 
1369
- if (packed_reload(backend) < 0 || /* load the existing packfile */
1370
- packed_loadloose(backend) < 0 || /* add all the loose refs */
1371
- packed_write(backend) < 0) /* write back to disk */
1372
- return -1;
1396
+ if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */
1397
+ (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */
1398
+ (error = packed_write(backend)) < 0) /* write back to disk */
1399
+ return error;
1373
1400
 
1374
1401
  return 0;
1375
1402
  }
@@ -1789,9 +1816,10 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
1789
1816
  * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1790
1817
  */
1791
1818
  if (git_path_isdir(git_buf_cstr(&path))) {
1792
- if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
1793
- error = -1;
1794
- else if (git_path_isdir(git_buf_cstr(&path))) {
1819
+ if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
1820
+ if (error == GIT_ENOTFOUND)
1821
+ error = 0;
1822
+ } else if (git_path_isdir(git_buf_cstr(&path))) {
1795
1823
  giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
1796
1824
  ref->name);
1797
1825
  error = GIT_EDIRECTORY;