rugged 0.24.6.1 → 0.25.0b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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