rugged 0.24.6.1 → 0.25.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_repo.c +44 -36
  3. data/lib/rugged/version.rb +1 -1
  4. data/vendor/libgit2/CMakeLists.txt +10 -21
  5. data/vendor/libgit2/include/git2/checkout.h +0 -7
  6. data/vendor/libgit2/include/git2/commit.h +46 -0
  7. data/vendor/libgit2/include/git2/common.h +1 -16
  8. data/vendor/libgit2/include/git2/odb.h +47 -1
  9. data/vendor/libgit2/include/git2/version.h +2 -2
  10. data/vendor/libgit2/src/array.h +0 -40
  11. data/vendor/libgit2/src/blame.c +3 -8
  12. data/vendor/libgit2/src/blame_git.c +9 -20
  13. data/vendor/libgit2/src/checkout.c +5 -13
  14. data/vendor/libgit2/src/commit.c +132 -52
  15. data/vendor/libgit2/src/common.h +1 -1
  16. data/vendor/libgit2/src/config_cache.c +1 -2
  17. data/vendor/libgit2/src/config_file.c +20 -14
  18. data/vendor/libgit2/src/delta-apply.c +5 -36
  19. data/vendor/libgit2/src/delta-apply.h +0 -12
  20. data/vendor/libgit2/src/describe.c +1 -2
  21. data/vendor/libgit2/src/diff_tform.c +3 -5
  22. data/vendor/libgit2/src/filebuf.c +1 -6
  23. data/vendor/libgit2/src/global.c +8 -28
  24. data/vendor/libgit2/src/global.h +0 -1
  25. data/vendor/libgit2/src/ignore.c +19 -56
  26. data/vendor/libgit2/src/index.c +8 -27
  27. data/vendor/libgit2/src/indexer.c +7 -11
  28. data/vendor/libgit2/src/iterator.c +2 -2
  29. data/vendor/libgit2/src/merge.c +0 -1
  30. data/vendor/libgit2/src/mwindow.c +19 -8
  31. data/vendor/libgit2/src/mwindow.h +2 -1
  32. data/vendor/libgit2/src/object.c +6 -3
  33. data/vendor/libgit2/src/odb.c +188 -48
  34. data/vendor/libgit2/src/odb_loose.c +1 -1
  35. data/vendor/libgit2/src/odb_pack.c +3 -0
  36. data/vendor/libgit2/src/openssl_stream.c +27 -60
  37. data/vendor/libgit2/src/openssl_stream.h +0 -106
  38. data/vendor/libgit2/src/pack-objects.c +2 -4
  39. data/vendor/libgit2/src/pack.c +9 -5
  40. data/vendor/libgit2/src/posix.c +0 -7
  41. data/vendor/libgit2/src/posix.h +0 -1
  42. data/vendor/libgit2/src/push.c +6 -6
  43. data/vendor/libgit2/src/refdb_fs.c +0 -1
  44. data/vendor/libgit2/src/refs.c +0 -3
  45. data/vendor/libgit2/src/refspec.c +2 -4
  46. data/vendor/libgit2/src/remote.c +5 -15
  47. data/vendor/libgit2/src/repository.c +21 -29
  48. data/vendor/libgit2/src/settings.c +1 -23
  49. data/vendor/libgit2/src/stransport_stream.c +9 -15
  50. data/vendor/libgit2/src/submodule.c +2 -3
  51. data/vendor/libgit2/src/sysdir.c +47 -41
  52. data/vendor/libgit2/src/sysdir.h +5 -0
  53. data/vendor/libgit2/src/tag.c +2 -8
  54. data/vendor/libgit2/src/thread-utils.h +51 -5
  55. data/vendor/libgit2/src/transports/http.c +3 -3
  56. data/vendor/libgit2/src/transports/smart_pkt.c +4 -13
  57. data/vendor/libgit2/src/transports/smart_protocol.c +17 -61
  58. data/vendor/libgit2/src/tree.c +100 -83
  59. data/vendor/libgit2/src/tree.h +5 -4
  60. data/vendor/libgit2/src/unix/map.c +0 -5
  61. data/vendor/libgit2/src/util.c +3 -3
  62. data/vendor/libgit2/src/win32/map.c +5 -24
  63. data/vendor/libgit2/src/win32/precompiled.h +1 -1
  64. data/vendor/libgit2/src/win32/{thread.c → pthread.c} +80 -50
  65. data/vendor/libgit2/src/win32/pthread.h +92 -0
  66. data/vendor/libgit2/src/xdiff/xprepare.c +1 -2
  67. metadata +7 -8
  68. data/vendor/libgit2/src/unix/pthread.h +0 -54
  69. data/vendor/libgit2/src/win32/thread.h +0 -62
@@ -137,14 +137,8 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
137
137
 
138
138
  tag->message = NULL;
139
139
  if (buffer < buffer_end) {
140
- /* If we're not at the end of the header, search for it */
141
- if( *buffer != '\n' ) {
142
- search = strstr(buffer, "\n\n");
143
- if (search)
144
- buffer = search + 1;
145
- else
146
- return tag_error("tag contains no message");
147
- }
140
+ if( *buffer != '\n' )
141
+ return tag_error("No new line before message");
148
142
 
149
143
  text_len = buffer_end - ++buffer;
150
144
 
@@ -40,12 +40,58 @@ typedef git_atomic git_atomic_ssize;
40
40
 
41
41
  #ifdef GIT_THREADS
42
42
 
43
- #ifdef GIT_WIN32
44
- # include "win32/thread.h"
45
- #else
46
- # include "unix/pthread.h"
43
+ #if !defined(GIT_WIN32)
44
+
45
+ typedef struct {
46
+ pthread_t thread;
47
+ } git_thread;
48
+
49
+ #define git_thread_create(git_thread_ptr, attr, start_routine, arg) \
50
+ pthread_create(&(git_thread_ptr)->thread, attr, start_routine, arg)
51
+ #define git_thread_join(git_thread_ptr, status) \
52
+ pthread_join((git_thread_ptr)->thread, status)
53
+
47
54
  #endif
48
55
 
56
+ /* Pthreads Mutex */
57
+ #define git_mutex pthread_mutex_t
58
+ #define git_mutex_init(a) pthread_mutex_init(a, NULL)
59
+ #define git_mutex_lock(a) pthread_mutex_lock(a)
60
+ #define git_mutex_unlock(a) pthread_mutex_unlock(a)
61
+ #define git_mutex_free(a) pthread_mutex_destroy(a)
62
+
63
+ /* Pthreads condition vars */
64
+ #define git_cond pthread_cond_t
65
+ #define git_cond_init(c) pthread_cond_init(c, NULL)
66
+ #define git_cond_free(c) pthread_cond_destroy(c)
67
+ #define git_cond_wait(c, l) pthread_cond_wait(c, l)
68
+ #define git_cond_signal(c) pthread_cond_signal(c)
69
+ #define git_cond_broadcast(c) pthread_cond_broadcast(c)
70
+
71
+ /* Pthread (-ish) rwlock
72
+ *
73
+ * This differs from normal pthreads rwlocks in two ways:
74
+ * 1. Separate APIs for releasing read locks and write locks (as
75
+ * opposed to the pure POSIX API which only has one unlock fn)
76
+ * 2. You should not use recursive read locks (i.e. grabbing a read
77
+ * lock in a thread that already holds a read lock) because the
78
+ * Windows implementation doesn't support it
79
+ */
80
+ #define git_rwlock pthread_rwlock_t
81
+ #define git_rwlock_init(a) pthread_rwlock_init(a, NULL)
82
+ #define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a)
83
+ #define git_rwlock_rdunlock(a) pthread_rwlock_rdunlock(a)
84
+ #define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a)
85
+ #define git_rwlock_wrunlock(a) pthread_rwlock_wrunlock(a)
86
+ #define git_rwlock_free(a) pthread_rwlock_destroy(a)
87
+ #define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER
88
+
89
+ #ifndef GIT_WIN32
90
+ #define pthread_rwlock_rdunlock pthread_rwlock_unlock
91
+ #define pthread_rwlock_wrunlock pthread_rwlock_unlock
92
+ #endif
93
+
94
+
49
95
  GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
50
96
  {
51
97
  #if defined(GIT_WIN32)
@@ -132,7 +178,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
132
178
  #else
133
179
 
134
180
  #define git_thread unsigned int
135
- #define git_thread_create(thread, start_routine, arg) 0
181
+ #define git_thread_create(thread, attr, start_routine, arg) 0
136
182
  #define git_thread_join(id, status) (void)0
137
183
 
138
184
  /* Pthreads Mutex */
@@ -114,7 +114,7 @@ static bool challenge_match(git_http_auth_scheme *scheme, void *data)
114
114
  size_t scheme_len;
115
115
 
116
116
  scheme_len = strlen(scheme_name);
117
- return (strncasecmp(challenge, scheme_name, scheme_len) == 0 &&
117
+ return (strncmp(challenge, scheme_name, scheme_len) == 0 &&
118
118
  (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '));
119
119
  }
120
120
 
@@ -569,7 +569,6 @@ static int http_connect(http_subtransport *t)
569
569
  git_stream_close(t->io);
570
570
  git_stream_free(t->io);
571
571
  t->io = NULL;
572
- t->connected = 0;
573
572
  }
574
573
 
575
574
  if (t->connection_data.use_ssl) {
@@ -602,12 +601,13 @@ static int http_connect(http_subtransport *t)
602
601
  if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL &&
603
602
  git_stream_is_encrypted(t->io)) {
604
603
  git_cert *cert;
605
- int is_valid = (error == GIT_OK);
604
+ int is_valid;
606
605
 
607
606
  if ((error = git_stream_certificate(&cert, t->io)) < 0)
608
607
  return error;
609
608
 
610
609
  giterr_clear();
610
+ is_valid = error != GIT_ECERTIFICATE;
611
611
  error = t->owner->certificate_check_cb(cert, is_valid, t->connection_data.host, t->owner->message_cb_payload);
612
612
 
613
613
  if (error < 0) {
@@ -427,23 +427,14 @@ int git_pkt_parse_line(
427
427
  if (bufflen > 0 && bufflen < (size_t)len)
428
428
  return GIT_EBUFS;
429
429
 
430
- /*
431
- * The length has to be exactly 0 in case of a flush
432
- * packet or greater than PKT_LEN_SIZE, as the decoded
433
- * length includes its own encoded length of four bytes.
434
- */
435
- if (len != 0 && len < PKT_LEN_SIZE)
436
- return GIT_ERROR;
437
-
438
430
  line += PKT_LEN_SIZE;
439
431
  /*
440
- * The Git protocol does not specify empty lines as part
441
- * of the protocol. Not knowing what to do with an empty
442
- * line, we should return an error upon hitting one.
432
+ * TODO: How do we deal with empty lines? Try again? with the next
433
+ * line?
443
434
  */
444
435
  if (len == PKT_LEN_SIZE) {
445
- giterr_set_str(GITERR_NET, "Invalid empty packet");
446
- return GIT_ERROR;
436
+ *out = line;
437
+ return 0;
447
438
  }
448
439
 
449
440
  if (len == 0) { /* Flush pkt */
@@ -721,39 +721,18 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
721
721
  return 0;
722
722
  }
723
723
 
724
- static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_buf *data_pkt_buf)
724
+ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt)
725
725
  {
726
726
  git_pkt *pkt;
727
- const char *line, *line_end;
728
- size_t line_len;
727
+ const char *line = data_pkt->data, *line_end;
728
+ size_t line_len = data_pkt->len;
729
729
  int error;
730
- int reading_from_buf = data_pkt_buf->size > 0;
731
-
732
- if (reading_from_buf) {
733
- /* We had an existing partial packet, so add the new
734
- * packet to the buffer and parse the whole thing */
735
- git_buf_put(data_pkt_buf, data_pkt->data, data_pkt->len);
736
- line = data_pkt_buf->ptr;
737
- line_len = data_pkt_buf->size;
738
- }
739
- else {
740
- line = data_pkt->data;
741
- line_len = data_pkt->len;
742
- }
743
730
 
744
731
  while (line_len > 0) {
745
732
  error = git_pkt_parse_line(&pkt, line, &line_end, line_len);
746
733
 
747
- if (error == GIT_EBUFS) {
748
- /* Buffer the data when the inner packet is split
749
- * across multiple sideband packets */
750
- if (!reading_from_buf)
751
- git_buf_put(data_pkt_buf, line, line_len);
752
- error = 0;
753
- goto done;
754
- }
755
- else if (error < 0)
756
- goto done;
734
+ if (error < 0)
735
+ return error;
757
736
 
758
737
  /* Advance in the buffer */
759
738
  line_len -= (line_end - line);
@@ -764,15 +743,10 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
764
743
  git_pkt_free(pkt);
765
744
 
766
745
  if (error < 0 && error != GIT_ITEROVER)
767
- goto done;
746
+ return error;
768
747
  }
769
748
 
770
- error = 0;
771
-
772
- done:
773
- if (reading_from_buf)
774
- git_buf_consume(data_pkt_buf, line_end);
775
- return error;
749
+ return 0;
776
750
  }
777
751
 
778
752
  static int parse_report(transport_smart *transport, git_push *push)
@@ -781,7 +755,6 @@ static int parse_report(transport_smart *transport, git_push *push)
781
755
  const char *line_end = NULL;
782
756
  gitno_buffer *buf = &transport->buffer;
783
757
  int error, recvd;
784
- git_buf data_pkt_buf = GIT_BUF_INIT;
785
758
 
786
759
  for (;;) {
787
760
  if (buf->offset > 0)
@@ -790,21 +763,16 @@ static int parse_report(transport_smart *transport, git_push *push)
790
763
  else
791
764
  error = GIT_EBUFS;
792
765
 
793
- if (error < 0 && error != GIT_EBUFS) {
794
- error = -1;
795
- goto done;
796
- }
766
+ if (error < 0 && error != GIT_EBUFS)
767
+ return -1;
797
768
 
798
769
  if (error == GIT_EBUFS) {
799
- if ((recvd = gitno_recv(buf)) < 0) {
800
- error = recvd;
801
- goto done;
802
- }
770
+ if ((recvd = gitno_recv(buf)) < 0)
771
+ return recvd;
803
772
 
804
773
  if (recvd == 0) {
805
774
  giterr_set(GITERR_NET, "early EOF");
806
- error = GIT_EEOF;
807
- goto done;
775
+ return GIT_EEOF;
808
776
  }
809
777
  continue;
810
778
  }
@@ -816,7 +784,7 @@ static int parse_report(transport_smart *transport, git_push *push)
816
784
  switch (pkt->type) {
817
785
  case GIT_PKT_DATA:
818
786
  /* This is a sideband packet which contains other packets */
819
- error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt, &data_pkt_buf);
787
+ error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt);
820
788
  break;
821
789
  case GIT_PKT_ERR:
822
790
  giterr_set(GITERR_NET, "report-status: Error reported: %s",
@@ -837,24 +805,12 @@ static int parse_report(transport_smart *transport, git_push *push)
837
805
  git_pkt_free(pkt);
838
806
 
839
807
  /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
840
- if (error == GIT_ITEROVER) {
841
- error = 0;
842
- if (data_pkt_buf.size > 0) {
843
- /* If there was data remaining in the pack data buffer,
844
- * then the server sent a partial pkt-line */
845
- giterr_set(GITERR_NET, "Incomplete pack data pkt-line");
846
- error = GIT_ERROR;
847
- }
848
- goto done;
849
- }
808
+ if (error == GIT_ITEROVER)
809
+ return 0;
850
810
 
851
- if (error < 0) {
852
- goto done;
853
- }
811
+ if (error < 0)
812
+ return error;
854
813
  }
855
- done:
856
- git_buf_free(&data_pkt_buf);
857
- return error;
858
814
  }
859
815
 
860
816
  static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
@@ -45,7 +45,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
45
45
  if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT)
46
46
  return GIT_FILEMODE_COMMIT;
47
47
 
48
- /* 12XXXX means symlink */
48
+ /* 12XXXX means commit */
49
49
  if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK)
50
50
  return GIT_FILEMODE_LINK;
51
51
 
@@ -85,10 +85,9 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
85
85
  }
86
86
 
87
87
  /**
88
- * Allocate a new self-contained entry, with enough space after it to
89
- * store the filename and the id.
88
+ * Allocate either from the pool or from the system allocator
90
89
  */
91
- static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id)
90
+ static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, size_t filename_len)
92
91
  {
93
92
  git_tree_entry *entry = NULL;
94
93
  size_t tree_len;
@@ -96,32 +95,44 @@ static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, co
96
95
  TREE_ENTRY_CHECK_NAMELEN(filename_len);
97
96
 
98
97
  if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
99
- GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
100
- GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ))
98
+ GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1))
101
99
  return NULL;
102
100
 
103
- entry = git__calloc(1, tree_len);
101
+ entry = pool ? git_pool_malloc(pool, tree_len) :
102
+ git__malloc(tree_len);
104
103
  if (!entry)
105
104
  return NULL;
106
105
 
107
- {
108
- char *filename_ptr;
109
- void *id_ptr;
106
+ memset(entry, 0x0, sizeof(git_tree_entry));
107
+ memcpy(entry->filename, filename, filename_len);
108
+ entry->filename[filename_len] = 0;
109
+ entry->filename_len = (uint16_t)filename_len;
110
110
 
111
- filename_ptr = ((char *) entry) + sizeof(git_tree_entry);
112
- memcpy(filename_ptr, filename, filename_len);
113
- entry->filename = filename_ptr;
111
+ return entry;
112
+ }
114
113
 
115
- id_ptr = filename_ptr + filename_len + 1;
116
- git_oid_cpy(id_ptr, id);
117
- entry->oid = id_ptr;
118
- }
114
+ /**
115
+ * Allocate a tree entry, using the poolin the tree which owns
116
+ * it. This is useful when reading trees, so we don't allocate a ton
117
+ * of small strings but can use the pool.
118
+ */
119
+ static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len)
120
+ {
121
+ git_tree_entry *entry = NULL;
119
122
 
120
- entry->filename_len = (uint16_t)filename_len;
123
+ if (!(entry = alloc_entry_base(pool, filename, filename_len)))
124
+ return NULL;
125
+
126
+ entry->pooled = true;
121
127
 
122
128
  return entry;
123
129
  }
124
130
 
131
+ static git_tree_entry *alloc_entry(const char *filename)
132
+ {
133
+ return alloc_entry_base(NULL, filename, strlen(filename));
134
+ }
135
+
125
136
  struct tree_key_search {
126
137
  const char *filename;
127
138
  uint16_t filename_len;
@@ -163,10 +174,7 @@ static int homing_search_cmp(const void *key, const void *array_member)
163
174
  * around the area for our target file.
164
175
  */
165
176
  static int tree_key_search(
166
- size_t *at_pos,
167
- const git_tree *tree,
168
- const char *filename,
169
- size_t filename_len)
177
+ size_t *at_pos, git_vector *entries, const char *filename, size_t filename_len)
170
178
  {
171
179
  struct tree_key_search ksearch;
172
180
  const git_tree_entry *entry;
@@ -179,15 +187,13 @@ static int tree_key_search(
179
187
 
180
188
  /* Initial homing search; find an entry on the tree with
181
189
  * the same prefix as the filename we're looking for */
182
-
183
- if (git_array_search(&homing,
184
- tree->entries, &homing_search_cmp, &ksearch) < 0)
190
+ if (git_vector_bsearch2(&homing, entries, &homing_search_cmp, &ksearch) < 0)
185
191
  return GIT_ENOTFOUND; /* just a signal error; not passed back to user */
186
192
 
187
193
  /* We found a common prefix. Look forward as long as
188
194
  * there are entries that share the common prefix */
189
- for (i = homing; i < tree->entries.size; ++i) {
190
- entry = git_array_get(tree->entries, i);
195
+ for (i = homing; i < entries->length; ++i) {
196
+ entry = entries->contents[i];
191
197
 
192
198
  if (homing_search_cmp(&ksearch, entry) < 0)
193
199
  break;
@@ -207,7 +213,7 @@ static int tree_key_search(
207
213
  i = homing - 1;
208
214
 
209
215
  do {
210
- entry = git_array_get(tree->entries, i);
216
+ entry = entries->contents[i];
211
217
 
212
218
  if (homing_search_cmp(&ksearch, entry) > 0)
213
219
  break;
@@ -228,7 +234,7 @@ static int tree_key_search(
228
234
 
229
235
  void git_tree_entry_free(git_tree_entry *entry)
230
236
  {
231
- if (entry == NULL)
237
+ if (entry == NULL || entry->pooled)
232
238
  return;
233
239
 
234
240
  git__free(entry);
@@ -236,26 +242,36 @@ void git_tree_entry_free(git_tree_entry *entry)
236
242
 
237
243
  int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source)
238
244
  {
239
- git_tree_entry *cpy;
245
+ size_t total_size;
246
+ git_tree_entry *copy;
240
247
 
241
248
  assert(source);
242
249
 
243
- cpy = alloc_entry(source->filename, source->filename_len, source->oid);
244
- if (cpy == NULL)
245
- return -1;
250
+ GITERR_CHECK_ALLOC_ADD(&total_size, sizeof(git_tree_entry), source->filename_len);
251
+ GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
246
252
 
247
- cpy->attr = source->attr;
253
+ copy = git__malloc(total_size);
254
+ GITERR_CHECK_ALLOC(copy);
248
255
 
249
- *dest = cpy;
256
+ memcpy(copy, source, total_size);
257
+
258
+ copy->pooled = 0;
259
+
260
+ *dest = copy;
250
261
  return 0;
251
262
  }
252
263
 
253
264
  void git_tree__free(void *_tree)
254
265
  {
255
266
  git_tree *tree = _tree;
267
+ size_t i;
268
+ git_tree_entry *e;
269
+
270
+ git_vector_foreach(&tree->entries, i, e)
271
+ git_tree_entry_free(e);
256
272
 
257
- git_odb_object_free(tree->odb_obj);
258
- git_array_clear(tree->entries);
273
+ git_vector_free(&tree->entries);
274
+ git_pool_clear(&tree->pool);
259
275
  git__free(tree);
260
276
  }
261
277
 
@@ -278,7 +294,7 @@ const char *git_tree_entry_name(const git_tree_entry *entry)
278
294
  const git_oid *git_tree_entry_id(const git_tree_entry *entry)
279
295
  {
280
296
  assert(entry);
281
- return entry->oid;
297
+ return &entry->oid;
282
298
  }
283
299
 
284
300
  git_otype git_tree_entry_type(const git_tree_entry *entry)
@@ -299,7 +315,7 @@ int git_tree_entry_to_object(
299
315
  const git_tree_entry *entry)
300
316
  {
301
317
  assert(entry && object_out);
302
- return git_object_lookup(object_out, repo, entry->oid, GIT_OBJ_ANY);
318
+ return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
303
319
  }
304
320
 
305
321
  static const git_tree_entry *entry_fromname(
@@ -307,10 +323,13 @@ static const git_tree_entry *entry_fromname(
307
323
  {
308
324
  size_t idx;
309
325
 
310
- if (tree_key_search(&idx, tree, name, name_len) < 0)
326
+ /* be safe when we cast away constness - i.e. don't trigger a sort */
327
+ assert(git_vector_is_sorted(&tree->entries));
328
+
329
+ if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0)
311
330
  return NULL;
312
331
 
313
- return git_array_get(tree->entries, idx);
332
+ return git_vector_get(&tree->entries, idx);
314
333
  }
315
334
 
316
335
  const git_tree_entry *git_tree_entry_byname(
@@ -325,7 +344,7 @@ const git_tree_entry *git_tree_entry_byindex(
325
344
  const git_tree *tree, size_t idx)
326
345
  {
327
346
  assert(tree);
328
- return git_array_get(tree->entries, idx);
347
+ return git_vector_get(&tree->entries, idx);
329
348
  }
330
349
 
331
350
  const git_tree_entry *git_tree_entry_byid(
@@ -336,8 +355,8 @@ const git_tree_entry *git_tree_entry_byid(
336
355
 
337
356
  assert(tree);
338
357
 
339
- git_array_foreach(tree->entries, i, e) {
340
- if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0)
358
+ git_vector_foreach(&tree->entries, i, e) {
359
+ if (memcmp(&e->oid.id, &id->id, sizeof(id->id)) == 0)
341
360
  return e;
342
361
  }
343
362
 
@@ -346,6 +365,7 @@ const git_tree_entry *git_tree_entry_byid(
346
365
 
347
366
  int git_tree__prefix_position(const git_tree *tree, const char *path)
348
367
  {
368
+ const git_vector *entries = &tree->entries;
349
369
  struct tree_key_search ksearch;
350
370
  size_t at_pos, path_len;
351
371
 
@@ -358,20 +378,21 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
358
378
  ksearch.filename = path;
359
379
  ksearch.filename_len = (uint16_t)path_len;
360
380
 
381
+ /* be safe when we cast away constness - i.e. don't trigger a sort */
382
+ assert(git_vector_is_sorted(&tree->entries));
383
+
361
384
  /* Find tree entry with appropriate prefix */
362
- git_array_search(
363
- &at_pos, tree->entries, &homing_search_cmp, &ksearch);
385
+ git_vector_bsearch2(
386
+ &at_pos, (git_vector *)entries, &homing_search_cmp, &ksearch);
364
387
 
365
- for (; at_pos < tree->entries.size; ++at_pos) {
366
- const git_tree_entry *entry = git_array_get(tree->entries, at_pos);
388
+ for (; at_pos < entries->length; ++at_pos) {
389
+ const git_tree_entry *entry = entries->contents[at_pos];
367
390
  if (homing_search_cmp(&ksearch, entry) < 0)
368
391
  break;
369
392
  }
370
393
 
371
394
  for (; at_pos > 0; --at_pos) {
372
- const git_tree_entry *entry =
373
- git_array_get(tree->entries, at_pos - 1);
374
-
395
+ const git_tree_entry *entry = entries->contents[at_pos - 1];
375
396
  if (homing_search_cmp(&ksearch, entry) > 0)
376
397
  break;
377
398
  }
@@ -382,7 +403,7 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
382
403
  size_t git_tree_entrycount(const git_tree *tree)
383
404
  {
384
405
  assert(tree);
385
- return tree->entries.size;
406
+ return tree->entries.length;
386
407
  }
387
408
 
388
409
  unsigned int git_treebuilder_entrycount(git_treebuilder *bld)
@@ -423,18 +444,13 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff
423
444
  int git_tree__parse(void *_tree, git_odb_object *odb_obj)
424
445
  {
425
446
  git_tree *tree = _tree;
426
- const char *buffer;
427
- const char *buffer_end;
447
+ const char *buffer = git_odb_object_data(odb_obj);
448
+ const char *buffer_end = buffer + git_odb_object_size(odb_obj);
428
449
 
429
- if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0)
450
+ git_pool_init(&tree->pool, 1);
451
+ if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0)
430
452
  return -1;
431
453
 
432
- buffer = git_odb_object_data(tree->odb_obj);
433
- buffer_end = buffer + git_odb_object_size(tree->odb_obj);
434
-
435
- git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE);
436
- GITERR_CHECK_ARRAY(tree->entries);
437
-
438
454
  while (buffer < buffer_end) {
439
455
  git_tree_entry *entry;
440
456
  size_t filename_len;
@@ -447,27 +463,28 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
447
463
  if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
448
464
  return tree_error("Failed to parse tree. Object is corrupted", NULL);
449
465
 
450
- if ((filename_len = nul - buffer) == 0)
451
- return tree_error("Failed to parse tree. Can't parse filename", NULL);
452
-
453
- if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ)
454
- return tree_error("Failed to parse tree. Can't parse OID", NULL);
455
-
456
- /* Allocate the entry */
466
+ filename_len = nul - buffer;
467
+ /** Allocate the entry and store it in the entries vector */
457
468
  {
458
- entry = git_array_alloc(tree->entries);
469
+ entry = alloc_entry_pooled(&tree->pool, buffer, filename_len);
459
470
  GITERR_CHECK_ALLOC(entry);
460
471
 
472
+ if (git_vector_insert(&tree->entries, entry) < 0)
473
+ return -1;
474
+
461
475
  entry->attr = attr;
462
- entry->filename_len = filename_len;
463
- entry->filename = buffer;
464
- entry->oid = (git_oid *) ((char *) buffer + filename_len + 1);
465
476
  }
466
477
 
478
+ /* Advance to the ID just after the path */
467
479
  buffer += filename_len + 1;
480
+
481
+ git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
468
482
  buffer += GIT_OID_RAWSZ;
469
483
  }
470
484
 
485
+ /* The tree is sorted by definition. Bad inputs give bad outputs */
486
+ tree->entries.flags |= GIT_VECTOR_SORTED;
487
+
471
488
  return 0;
472
489
  }
473
490
 
@@ -500,9 +517,10 @@ static int append_entry(
500
517
  if (!valid_entry_name(bld->repo, filename))
501
518
  return tree_error("Failed to insert entry. Invalid name for a tree entry", filename);
502
519
 
503
- entry = alloc_entry(filename, strlen(filename), id);
520
+ entry = alloc_entry(filename);
504
521
  GITERR_CHECK_ALLOC(entry);
505
522
 
523
+ git_oid_cpy(&entry->oid, id);
506
524
  entry->attr = (uint16_t)filemode;
507
525
 
508
526
  git_strmap_insert(bld->map, entry->filename, entry, error);
@@ -691,10 +709,10 @@ int git_treebuilder_new(
691
709
  if (source != NULL) {
692
710
  git_tree_entry *entry_src;
693
711
 
694
- git_array_foreach(source->entries, i, entry_src) {
712
+ git_vector_foreach(&source->entries, i, entry_src) {
695
713
  if (append_entry(
696
714
  bld, entry_src->filename,
697
- entry_src->oid,
715
+ &entry_src->oid,
698
716
  entry_src->attr) < 0)
699
717
  goto on_error;
700
718
  }
@@ -746,9 +764,8 @@ int git_treebuilder_insert(
746
764
  pos = git_strmap_lookup_index(bld->map, filename);
747
765
  if (git_strmap_valid_index(bld->map, pos)) {
748
766
  entry = git_strmap_value_at(bld->map, pos);
749
- git_oid_cpy((git_oid *) entry->oid, id);
750
767
  } else {
751
- entry = alloc_entry(filename, strlen(filename), id);
768
+ entry = alloc_entry(filename);
752
769
  GITERR_CHECK_ALLOC(entry);
753
770
 
754
771
  git_strmap_insert(bld->map, entry->filename, entry, error);
@@ -760,6 +777,7 @@ int git_treebuilder_insert(
760
777
  }
761
778
  }
762
779
 
780
+ git_oid_cpy(&entry->oid, id);
763
781
  entry->attr = filemode;
764
782
 
765
783
  if (entry_out)
@@ -830,20 +848,19 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
830
848
 
831
849
  git_buf_printf(&tree, "%o ", entry->attr);
832
850
  git_buf_put(&tree, entry->filename, entry->filename_len + 1);
833
- git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
851
+ git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ);
834
852
 
835
853
  if (git_buf_oom(&tree))
836
854
  error = -1;
837
855
  }
838
856
 
857
+ git_vector_free(&entries);
839
858
 
840
859
  if (!error &&
841
860
  !(error = git_repository_odb__weakptr(&odb, bld->repo)))
842
861
  error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
843
862
 
844
863
  git_buf_free(&tree);
845
- git_vector_free(&entries);
846
-
847
864
  return error;
848
865
  }
849
866
 
@@ -943,7 +960,7 @@ int git_tree_entry_bypath(
943
960
  return git_tree_entry_dup(entry_out, entry);
944
961
  }
945
962
 
946
- if (git_tree_lookup(&subtree, root->object.repo, entry->oid) < 0)
963
+ if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0)
947
964
  return -1;
948
965
 
949
966
  error = git_tree_entry_bypath(
@@ -967,7 +984,7 @@ static int tree_walk(
967
984
  size_t i;
968
985
  const git_tree_entry *entry;
969
986
 
970
- git_array_foreach(tree->entries, i, entry) {
987
+ git_vector_foreach(&tree->entries, i, entry) {
971
988
  if (preorder) {
972
989
  error = callback(path->ptr, entry, payload);
973
990
  if (error < 0) { /* negative value stops iteration */
@@ -984,7 +1001,7 @@ static int tree_walk(
984
1001
  git_tree *subtree;
985
1002
  size_t path_len = git_buf_len(path);
986
1003
 
987
- error = git_tree_lookup(&subtree, tree->object.repo, entry->oid);
1004
+ error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid);
988
1005
  if (error < 0)
989
1006
  break;
990
1007