rugged 0.23.3 → 0.24.0b0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/ext/rugged/rugged.c +24 -0
  4. data/ext/rugged/rugged_config.c +65 -0
  5. data/ext/rugged/rugged_remote.c +22 -2
  6. data/ext/rugged/rugged_repo.c +10 -5
  7. data/ext/rugged/rugged_tree.c +4 -1
  8. data/lib/rugged/version.rb +1 -1
  9. data/vendor/libgit2/CMakeLists.txt +47 -2
  10. data/vendor/libgit2/include/git2/config.h +18 -0
  11. data/vendor/libgit2/include/git2/diff.h +25 -2
  12. data/vendor/libgit2/include/git2/errors.h +0 -12
  13. data/vendor/libgit2/include/git2/index.h +11 -0
  14. data/vendor/libgit2/include/git2/remote.h +12 -1
  15. data/vendor/libgit2/include/git2/sys/config.h +14 -0
  16. data/vendor/libgit2/include/git2/sys/filter.h +4 -1
  17. data/vendor/libgit2/include/git2/sys/odb_backend.h +4 -0
  18. data/vendor/libgit2/include/git2/sys/refdb_backend.h +5 -4
  19. data/vendor/libgit2/include/git2/sys/transport.h +27 -0
  20. data/vendor/libgit2/include/git2/transport.h +25 -21
  21. data/vendor/libgit2/include/git2/version.h +2 -2
  22. data/vendor/libgit2/libgit2.pc.in +3 -2
  23. data/vendor/libgit2/src/branch.c +1 -12
  24. data/vendor/libgit2/src/checkout.c +29 -20
  25. data/vendor/libgit2/src/clone.c +2 -2
  26. data/vendor/libgit2/src/common.h +13 -4
  27. data/vendor/libgit2/src/config.c +36 -0
  28. data/vendor/libgit2/src/config.h +15 -0
  29. data/vendor/libgit2/src/config_file.c +124 -20
  30. data/vendor/libgit2/src/config_file.h +10 -0
  31. data/vendor/libgit2/src/curl_stream.c +7 -7
  32. data/vendor/libgit2/src/diff.c +89 -27
  33. data/vendor/libgit2/src/diff_print.c +1 -1
  34. data/vendor/libgit2/src/errors.c +75 -40
  35. data/vendor/libgit2/src/filebuf.c +81 -3
  36. data/vendor/libgit2/src/fileops.c +176 -75
  37. data/vendor/libgit2/src/fileops.h +7 -10
  38. data/vendor/libgit2/src/filter.c +5 -2
  39. data/vendor/libgit2/src/global.c +25 -9
  40. data/vendor/libgit2/src/global.h +1 -0
  41. data/vendor/libgit2/src/idxmap.h +92 -0
  42. data/vendor/libgit2/src/ignore.c +9 -7
  43. data/vendor/libgit2/src/index.c +246 -46
  44. data/vendor/libgit2/src/index.h +2 -0
  45. data/vendor/libgit2/src/iterator.c +377 -118
  46. data/vendor/libgit2/src/iterator.h +28 -20
  47. data/vendor/libgit2/src/merge.c +26 -13
  48. data/vendor/libgit2/src/notes.c +1 -1
  49. data/vendor/libgit2/src/odb.c +1 -2
  50. data/vendor/libgit2/src/odb_loose.c +2 -2
  51. data/vendor/libgit2/src/odb_mempack.c +6 -2
  52. data/vendor/libgit2/src/oidmap.h +2 -0
  53. data/vendor/libgit2/src/openssl_stream.c +9 -3
  54. data/vendor/libgit2/src/path.c +37 -2
  55. data/vendor/libgit2/src/path.h +12 -1
  56. data/vendor/libgit2/src/pathspec.c +12 -12
  57. data/vendor/libgit2/src/push.c +2 -1
  58. data/vendor/libgit2/src/push.h +1 -0
  59. data/vendor/libgit2/src/refdb.c +2 -6
  60. data/vendor/libgit2/src/refdb_fs.c +13 -3
  61. data/vendor/libgit2/src/remote.c +44 -15
  62. data/vendor/libgit2/src/repository.c +28 -12
  63. data/vendor/libgit2/src/stash.c +17 -12
  64. data/vendor/libgit2/src/stransport_stream.c +1 -1
  65. data/vendor/libgit2/src/submodule.c +234 -152
  66. data/vendor/libgit2/src/sysdir.c +22 -8
  67. data/vendor/libgit2/src/transaction.c +41 -0
  68. data/vendor/libgit2/src/transaction.h +14 -0
  69. data/vendor/libgit2/src/transports/cred.c +8 -0
  70. data/vendor/libgit2/src/transports/http.c +6 -0
  71. data/vendor/libgit2/src/transports/smart.c +95 -0
  72. data/vendor/libgit2/src/transports/smart.h +1 -0
  73. data/vendor/libgit2/src/transports/smart_pkt.c +9 -2
  74. data/vendor/libgit2/src/transports/ssh.c +5 -3
  75. data/vendor/libgit2/src/transports/winhttp.c +19 -1
  76. data/vendor/libgit2/src/unix/posix.h +14 -1
  77. data/vendor/libgit2/src/util.c +56 -13
  78. data/vendor/libgit2/src/util.h +13 -5
  79. data/vendor/libgit2/src/win32/path_w32.c +15 -8
  80. data/vendor/libgit2/src/win32/posix_w32.c +11 -2
  81. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
  82. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
  83. data/vendor/libgit2/src/win32/w32_stack.c +192 -0
  84. data/vendor/libgit2/src/win32/w32_stack.h +138 -0
  85. data/vendor/libgit2/src/win32/w32_util.c +29 -5
  86. data/vendor/libgit2/src/win32/w32_util.h +13 -3
  87. metadata +11 -5
@@ -55,12 +55,9 @@ extern int git_futils_creat_locked(const char *path, const mode_t mode);
55
55
  extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
56
56
 
57
57
  /**
58
- * Create a path recursively
59
- *
60
- * If a base parameter is being passed, it's expected to be valued with a
61
- * path pointing to an already existing directory.
58
+ * Create a path recursively.
62
59
  */
63
- extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode);
60
+ extern int git_futils_mkdir_r(const char *path, const mode_t mode);
64
61
 
65
62
  /**
66
63
  * Flags to pass to `git_futils_mkdir`.
@@ -111,20 +108,20 @@ struct git_futils_mkdir_options
111
108
  * and optionally chmods the directory immediately after (or each part of the
112
109
  * path if requested).
113
110
  *
114
- * @param path The path to create.
111
+ * @param path The path to create, relative to base.
115
112
  * @param base Root for relative path. These directories will never be made.
116
113
  * @param mode The mode to use for created directories.
117
114
  * @param flags Combination of the mkdir flags above.
118
- * @param opts Extended options, use `git_futils_mkdir` if you are not interested.
115
+ * @param opts Extended options, or null.
119
116
  * @return 0 on success, else error code
120
117
  */
121
- extern int git_futils_mkdir_ext(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
118
+ extern int git_futils_mkdir_relative(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
122
119
 
123
120
  /**
124
- * Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
121
+ * Create a directory or entire path. Similar to `git_futils_mkdir_relative`
125
122
  * without performance data.
126
123
  */
127
- extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags);
124
+ extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags);
128
125
 
129
126
  /**
130
127
  * Create all the folders required to contain
@@ -433,8 +433,11 @@ static int filter_list_check_attributes(
433
433
  want_type = git_attr_value(want);
434
434
  found_type = git_attr_value(strs[i]);
435
435
 
436
- if (want_type != found_type ||
437
- (want_type == GIT_ATTR_VALUE_T && strcmp(want, strs[i])))
436
+ if (want_type != found_type)
437
+ error = GIT_ENOTFOUND;
438
+ else if (want_type == GIT_ATTR_VALUE_T &&
439
+ strcmp(want, strs[i]) &&
440
+ strcmp(want, "*"))
438
441
  error = GIT_ENOTFOUND;
439
442
  }
440
443
 
@@ -11,7 +11,10 @@
11
11
  #include "git2/global.h"
12
12
  #include "git2/sys/openssl.h"
13
13
  #include "thread-utils.h"
14
-
14
+ #if defined(GIT_MSVC_CRTDBG)
15
+ #include "win32/w32_stack.h"
16
+ #include "win32/w32_crtdbg_stacktrace.h"
17
+ #endif
15
18
 
16
19
  git_mutex git__mwindow_mutex;
17
20
 
@@ -225,6 +228,11 @@ int git_libgit2_init(void)
225
228
 
226
229
  /* Only do work on a 0 -> 1 transition of the refcount */
227
230
  if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
231
+ #if defined(GIT_MSVC_CRTDBG)
232
+ git_win32__crtdbg_stacktrace_init();
233
+ git_win32__stack_init();
234
+ #endif
235
+
228
236
  if (synchronized_threads_init() < 0)
229
237
  ret = -1;
230
238
  }
@@ -254,9 +262,15 @@ int git_libgit2_shutdown(void)
254
262
  while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
255
263
 
256
264
  /* Only do work on a 1 -> 0 transition of the refcount */
257
- if ((ret = git_atomic_dec(&git__n_inits)) == 0)
265
+ if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
258
266
  synchronized_threads_shutdown();
259
267
 
268
+ #if defined(GIT_MSVC_CRTDBG)
269
+ git_win32__crtdbg_stacktrace_cleanup();
270
+ git_win32__stack_cleanup();
271
+ #endif
272
+ }
273
+
260
274
  /* Exit the lock */
261
275
  InterlockedExchange(&_mutex, 0);
262
276
 
@@ -265,18 +279,19 @@ int git_libgit2_shutdown(void)
265
279
 
266
280
  git_global_st *git__global_state(void)
267
281
  {
268
- void *ptr;
282
+ git_global_st *ptr;
269
283
 
270
284
  assert(git_atomic_get(&git__n_inits) > 0);
271
285
 
272
286
  if ((ptr = TlsGetValue(_tls_index)) != NULL)
273
287
  return ptr;
274
288
 
275
- ptr = git__malloc(sizeof(git_global_st));
289
+ ptr = git__calloc(1, sizeof(git_global_st));
276
290
  if (!ptr)
277
291
  return NULL;
278
292
 
279
- memset(ptr, 0x0, sizeof(git_global_st));
293
+ git_buf_init(&ptr->error_buf, 0);
294
+
280
295
  TlsSetValue(_tls_index, ptr);
281
296
  return ptr;
282
297
  }
@@ -330,8 +345,8 @@ int git_libgit2_init(void)
330
345
  {
331
346
  int ret;
332
347
 
333
- pthread_once(&_once_init, init_once);
334
348
  ret = git_atomic_inc(&git__n_inits);
349
+ pthread_once(&_once_init, init_once);
335
350
 
336
351
  return init_error ? init_error : ret;
337
352
  }
@@ -364,18 +379,18 @@ int git_libgit2_shutdown(void)
364
379
 
365
380
  git_global_st *git__global_state(void)
366
381
  {
367
- void *ptr;
382
+ git_global_st *ptr;
368
383
 
369
384
  assert(git_atomic_get(&git__n_inits) > 0);
370
385
 
371
386
  if ((ptr = pthread_getspecific(_tls_key)) != NULL)
372
387
  return ptr;
373
388
 
374
- ptr = git__malloc(sizeof(git_global_st));
389
+ ptr = git__calloc(1, sizeof(git_global_st));
375
390
  if (!ptr)
376
391
  return NULL;
377
392
 
378
- memset(ptr, 0x0, sizeof(git_global_st));
393
+ git_buf_init(&ptr->error_buf, 0);
379
394
  pthread_setspecific(_tls_key, ptr);
380
395
  return ptr;
381
396
  }
@@ -393,6 +408,7 @@ int git_libgit2_init(void)
393
408
  ssl_inited = 1;
394
409
  }
395
410
 
411
+ git_buf_init(&__state.error_buf, 0);
396
412
  return git_atomic_inc(&git__n_inits);
397
413
  }
398
414
 
@@ -14,6 +14,7 @@
14
14
  typedef struct {
15
15
  git_error *last_error;
16
16
  git_error error_t;
17
+ git_buf error_buf;
17
18
  char oid_fmt[GIT_OID_HEXSZ+1];
18
19
  } git_global_st;
19
20
 
@@ -0,0 +1,92 @@
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
+ #ifndef INCLUDE_idxmap_h__
8
+ #define INCLUDE_idxmap_h__
9
+
10
+ #include <ctype.h>
11
+ #include "common.h"
12
+ #include "git2/index.h"
13
+
14
+ #define kmalloc git__malloc
15
+ #define kcalloc git__calloc
16
+ #define krealloc git__realloc
17
+ #define kreallocarray git__reallocarray
18
+ #define kfree git__free
19
+ #include "khash.h"
20
+
21
+ __KHASH_TYPE(idx, const git_index_entry *, git_index_entry *)
22
+ __KHASH_TYPE(idxicase, const git_index_entry *, git_index_entry *)
23
+
24
+ typedef khash_t(idx) git_idxmap;
25
+ typedef khash_t(idxicase) git_idxmap_icase;
26
+
27
+ typedef khiter_t git_idxmap_iter;
28
+
29
+ /* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */
30
+ static kh_inline khint_t idxentry_hash(const git_index_entry *e)
31
+ {
32
+ const char *s = e->path;
33
+ khint_t h = (khint_t)git__tolower(*s);
34
+ if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s);
35
+ return h + GIT_IDXENTRY_STAGE(e);
36
+ }
37
+
38
+ #define idxentry_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcmp(a->path, b->path) == 0)
39
+ #define idxentry_icase_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0)
40
+
41
+ #define GIT__USE_IDXMAP \
42
+ __KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal)
43
+
44
+ #define GIT__USE_IDXMAP_ICASE \
45
+ __KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal)
46
+
47
+ #define git_idxmap_alloc(hp) \
48
+ ((*(hp) = kh_init(idx)) == NULL) ? giterr_set_oom(), -1 : 0
49
+
50
+ #define git_idxmap_icase_alloc(hp) \
51
+ ((*(hp) = kh_init(idxicase)) == NULL) ? giterr_set_oom(), -1 : 0
52
+
53
+ #define git_idxmap_insert(h, key, val, rval) do { \
54
+ khiter_t __pos = kh_put(idx, h, key, &rval); \
55
+ if (rval >= 0) { \
56
+ if (rval == 0) kh_key(h, __pos) = key; \
57
+ kh_val(h, __pos) = val; \
58
+ } } while (0)
59
+
60
+ #define git_idxmap_icase_insert(h, key, val, rval) do { \
61
+ khiter_t __pos = kh_put(idxicase, h, key, &rval); \
62
+ if (rval >= 0) { \
63
+ if (rval == 0) kh_key(h, __pos) = key; \
64
+ kh_val(h, __pos) = val; \
65
+ } } while (0)
66
+
67
+ #define git_idxmap_lookup_index(h, k) kh_get(idx, h, k)
68
+ #define git_idxmap_icase_lookup_index(h, k) kh_get(idxicase, h, k)
69
+ #define git_idxmap_value_at(h, idx) kh_val(h, idx)
70
+ #define git_idxmap_valid_index(h, idx) (idx != kh_end(h))
71
+ #define git_idxmap_has_data(h, idx) kh_exist(h, idx)
72
+
73
+ #define git_idxmap_free(h) kh_destroy(idx, h), h = NULL
74
+ #define git_idxmap_clear(h) kh_clear(idx, h)
75
+
76
+ #define git_idxmap_delete_at(h, id) kh_del(idx, h, id)
77
+ #define git_idxmap_icase_delete_at(h, id) kh_del(idxicase, h, id)
78
+
79
+ #define git_idxmap_delete(h, key) do { \
80
+ khiter_t __pos = git_idxmap_lookup_index(h, key); \
81
+ if (git_idxmap_valid_index(h, __pos)) \
82
+ git_idxmap_delete_at(h, __pos); } while (0)
83
+
84
+ #define git_idxmap_icase_delete(h, key) do { \
85
+ khiter_t __pos = git_idxmap_icase_lookup_index(h, key); \
86
+ if (git_idxmap_valid_index(h, __pos)) \
87
+ git_idxmap_icase_delete_at(h, __pos); } while (0)
88
+
89
+ #define git_idxmap_begin kh_begin
90
+ #define git_idxmap_end kh_end
91
+
92
+ #endif
@@ -89,18 +89,20 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
89
89
  }
90
90
 
91
91
  /*
92
- * If we're dealing with a directory (which we know via the
93
- * strchr() check) we want to use 'dirname/<star>' as the
94
- * pattern so p_fnmatch() honours FNM_PATHNAME
92
+ * When dealing with a directory, we add '/<star>' so
93
+ * p_fnmatch() honours FNM_PATHNAME. Checking for LEADINGDIR
94
+ * alone isn't enough as that's also set for nagations, so we
95
+ * need to check that NEGATIVE is off.
95
96
  */
96
97
  git_buf_clear(&buf);
97
98
  if (rule->containing_dir) {
98
99
  git_buf_puts(&buf, rule->containing_dir);
99
100
  }
100
- if (!strchr(rule->pattern, '*'))
101
- error = git_buf_printf(&buf, "%s/*", rule->pattern);
102
- else
103
- error = git_buf_puts(&buf, rule->pattern);
101
+
102
+ error = git_buf_puts(&buf, rule->pattern);
103
+
104
+ if ((rule->flags & (GIT_ATTR_FNMATCH_LEADINGDIR | GIT_ATTR_FNMATCH_NEGATIVE)) == GIT_ATTR_FNMATCH_LEADINGDIR)
105
+ error = git_buf_PUTS(&buf, "/*");
104
106
 
105
107
  if (error < 0)
106
108
  goto out;
@@ -17,6 +17,7 @@
17
17
  #include "pathspec.h"
18
18
  #include "ignore.h"
19
19
  #include "blob.h"
20
+ #include "idxmap.h"
20
21
 
21
22
  #include "git2/odb.h"
22
23
  #include "git2/oid.h"
@@ -24,6 +25,32 @@
24
25
  #include "git2/config.h"
25
26
  #include "git2/sys/index.h"
26
27
 
28
+ GIT__USE_IDXMAP
29
+ GIT__USE_IDXMAP_ICASE
30
+
31
+ #define INSERT_IN_MAP_EX(idx, map, e, err) do { \
32
+ if ((idx)->ignore_case) \
33
+ git_idxmap_icase_insert((khash_t(idxicase) *) (map), (e), (e), (err)); \
34
+ else \
35
+ git_idxmap_insert((map), (e), (e), (err)); \
36
+ } while (0)
37
+
38
+ #define INSERT_IN_MAP(idx, e, err) INSERT_IN_MAP_EX(idx, (idx)->entries_map, e, err)
39
+
40
+ #define LOOKUP_IN_MAP(p, idx, k) do { \
41
+ if ((idx)->ignore_case) \
42
+ (p) = git_idxmap_icase_lookup_index((khash_t(idxicase) *) index->entries_map, (k)); \
43
+ else \
44
+ (p) = git_idxmap_lookup_index(index->entries_map, (k)); \
45
+ } while (0)
46
+
47
+ #define DELETE_IN_MAP(idx, e) do { \
48
+ if ((idx)->ignore_case) \
49
+ git_idxmap_icase_delete((khash_t(idxicase) *) (idx)->entries_map, (e)); \
50
+ else \
51
+ git_idxmap_delete((idx)->entries_map, (e)); \
52
+ } while (0)
53
+
27
54
  static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
28
55
  unsigned int flags,
29
56
  git_index_matched_path_cb cb, void *payload);
@@ -425,6 +452,7 @@ int git_index_open(git_index **index_out, const char *index_path)
425
452
  }
426
453
 
427
454
  if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
455
+ git_idxmap_alloc(&index->entries_map) < 0 ||
428
456
  git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
429
457
  git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
430
458
  git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
@@ -462,6 +490,7 @@ static void index_free(git_index *index)
462
490
  assert(!git_atomic_get(&index->readers));
463
491
 
464
492
  git_index_clear(index);
493
+ git_idxmap_free(index->entries_map);
465
494
  git_vector_free(&index->entries);
466
495
  git_vector_free(&index->names);
467
496
  git_vector_free(&index->reuc);
@@ -508,6 +537,7 @@ static int index_remove_entry(git_index *index, size_t pos)
508
537
  if (entry != NULL)
509
538
  git_tree_cache_invalidate_path(index->tree, entry->path);
510
539
 
540
+ DELETE_IN_MAP(index, entry);
511
541
  error = git_vector_remove(&index->entries, pos);
512
542
 
513
543
  if (!error) {
@@ -535,6 +565,7 @@ int git_index_clear(git_index *index)
535
565
  return -1;
536
566
  }
537
567
 
568
+ git_idxmap_clear(index->entries_map);
538
569
  while (!error && index->entries.length > 0)
539
570
  error = index_remove_entry(index, index->entries.length - 1);
540
571
  index_free_deleted(index);
@@ -728,6 +759,7 @@ static int truncate_racily_clean(git_index *index)
728
759
  if (!is_racy_timestamp(ts, entry))
729
760
  continue;
730
761
 
762
+ /* TODO: use the (non-fnmatching) filelist iterator */
731
763
  diff_opts.pathspec.count = 1;
732
764
  diff_opts.pathspec.strings = (char **) &entry->path;
733
765
 
@@ -804,16 +836,21 @@ const git_index_entry *git_index_get_byindex(
804
836
  const git_index_entry *git_index_get_bypath(
805
837
  git_index *index, const char *path, int stage)
806
838
  {
807
- size_t pos;
839
+ khiter_t pos;
840
+ git_index_entry key = {{ 0 }};
808
841
 
809
842
  assert(index);
810
843
 
811
- if (index_find(&pos, index, path, 0, stage, true) < 0) {
812
- giterr_set(GITERR_INDEX, "Index does not contain %s", path);
813
- return NULL;
814
- }
844
+ key.path = path;
845
+ GIT_IDXENTRY_STAGE_SET(&key, stage);
846
+
847
+ LOOKUP_IN_MAP(pos, index, &key);
815
848
 
816
- return git_index_get_byindex(index, pos);
849
+ if (git_idxmap_valid_index(index->entries_map, pos))
850
+ return git_idxmap_value_at(index->entries_map, pos);
851
+
852
+ giterr_set(GITERR_INDEX, "Index does not contain %s", path);
853
+ return NULL;
817
854
  }
818
855
 
819
856
  void git_index_entry__init_from_stat(
@@ -940,16 +977,27 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
940
977
  return 0;
941
978
  }
942
979
 
943
- static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
980
+ static void index_entry_cpy(
981
+ git_index_entry *tgt,
982
+ git_index *index,
983
+ const git_index_entry *src,
984
+ bool update_path)
944
985
  {
945
986
  const char *tgt_path = tgt->path;
946
987
  memcpy(tgt, src, sizeof(*tgt));
947
- tgt->path = tgt_path; /* reset to existing path data */
988
+
989
+ /* keep the existing path buffer, but update the path to the one
990
+ * given by the caller, if we trust it.
991
+ */
992
+ tgt->path = tgt_path;
993
+
994
+ if (index->ignore_case && update_path)
995
+ memcpy((char *)tgt->path, src->path, strlen(tgt->path));
948
996
  }
949
997
 
950
998
  static int index_entry_dup(
951
999
  git_index_entry **out,
952
- git_repository *repo,
1000
+ git_index *index,
953
1001
  const git_index_entry *src)
954
1002
  {
955
1003
  git_index_entry *entry;
@@ -959,10 +1007,10 @@ static int index_entry_dup(
959
1007
  return 0;
960
1008
  }
961
1009
 
962
- if (index_entry_create(&entry, repo, src->path) < 0)
1010
+ if (index_entry_create(&entry, INDEX_OWNER(index), src->path) < 0)
963
1011
  return -1;
964
1012
 
965
- index_entry_cpy(entry, src);
1013
+ index_entry_cpy(entry, index, src, false);
966
1014
  *out = entry;
967
1015
  return 0;
968
1016
  }
@@ -1065,6 +1113,74 @@ static int check_file_directory_collision(git_index *index,
1065
1113
  return 0;
1066
1114
  }
1067
1115
 
1116
+ static int canonicalize_directory_path(
1117
+ git_index *index, git_index_entry *entry)
1118
+ {
1119
+ const git_index_entry *match, *best = NULL;
1120
+ char *search, *sep;
1121
+ size_t pos, search_len, best_len;
1122
+
1123
+ if (!index->ignore_case)
1124
+ return 0;
1125
+
1126
+ /* item already exists in the index, simply re-use the existing case */
1127
+ if ((match = git_index_get_bypath(index, entry->path, 0)) != NULL) {
1128
+ memcpy((char *)entry->path, match->path, strlen(entry->path));
1129
+ return 0;
1130
+ }
1131
+
1132
+ /* nothing to do */
1133
+ if (strchr(entry->path, '/') == NULL)
1134
+ return 0;
1135
+
1136
+ if ((search = git__strdup(entry->path)) == NULL)
1137
+ return -1;
1138
+
1139
+ /* starting at the parent directory and descending to the root, find the
1140
+ * common parent directory.
1141
+ */
1142
+ while (!best && (sep = strrchr(search, '/'))) {
1143
+ sep[1] = '\0';
1144
+
1145
+ search_len = strlen(search);
1146
+
1147
+ git_vector_bsearch2(
1148
+ &pos, &index->entries, index->entries_search_path, search);
1149
+
1150
+ while ((match = git_vector_get(&index->entries, pos))) {
1151
+ if (GIT_IDXENTRY_STAGE(match) != 0) {
1152
+ /* conflicts do not contribute to canonical paths */
1153
+ } else if (memcmp(search, match->path, search_len) == 0) {
1154
+ /* prefer an exact match to the input filename */
1155
+ best = match;
1156
+ best_len = search_len;
1157
+ break;
1158
+ } else if (strncasecmp(search, match->path, search_len) == 0) {
1159
+ /* continue walking, there may be a path with an exact
1160
+ * (case sensitive) match later in the index, but use this
1161
+ * as the best match until that happens.
1162
+ */
1163
+ if (!best) {
1164
+ best = match;
1165
+ best_len = search_len;
1166
+ }
1167
+ } else {
1168
+ break;
1169
+ }
1170
+
1171
+ pos++;
1172
+ }
1173
+
1174
+ sep[0] = '\0';
1175
+ }
1176
+
1177
+ if (best)
1178
+ memcpy((char *)entry->path, best->path, best_len);
1179
+
1180
+ git__free(search);
1181
+ return 0;
1182
+ }
1183
+
1068
1184
  static int index_no_dups(void **old, void *new)
1069
1185
  {
1070
1186
  const git_index_entry *entry = new;
@@ -1078,10 +1194,17 @@ static int index_no_dups(void **old, void *new)
1078
1194
  * it, then it will return an error **and also free the entry**. When
1079
1195
  * it replaces an existing entry, it will update the entry_ptr with the
1080
1196
  * actual entry in the index (and free the passed in one).
1197
+ * trust_path is whether we use the given path, or whether (on case
1198
+ * insensitive systems only) we try to canonicalize the given path to
1199
+ * be within an existing directory.
1081
1200
  * trust_mode is whether we trust the mode in entry_ptr.
1082
1201
  */
1083
1202
  static int index_insert(
1084
- git_index *index, git_index_entry **entry_ptr, int replace, bool trust_mode)
1203
+ git_index *index,
1204
+ git_index_entry **entry_ptr,
1205
+ int replace,
1206
+ bool trust_path,
1207
+ bool trust_mode)
1085
1208
  {
1086
1209
  int error = 0;
1087
1210
  size_t path_length, position;
@@ -1119,8 +1242,14 @@ static int index_insert(
1119
1242
  entry->mode = index_merge_mode(index, existing, entry->mode);
1120
1243
  }
1121
1244
 
1245
+ /* canonicalize the directory name */
1246
+ if (!trust_path)
1247
+ error = canonicalize_directory_path(index, entry);
1248
+
1122
1249
  /* look for tree / blob name collisions, removing conflicts if requested */
1123
- error = check_file_directory_collision(index, entry, position, replace);
1250
+ if (!error)
1251
+ error = check_file_directory_collision(index, entry, position, replace);
1252
+
1124
1253
  if (error < 0)
1125
1254
  /* skip changes */;
1126
1255
 
@@ -1129,7 +1258,7 @@ static int index_insert(
1129
1258
  */
1130
1259
  else if (existing) {
1131
1260
  if (replace)
1132
- index_entry_cpy(existing, entry);
1261
+ index_entry_cpy(existing, index, entry, trust_path);
1133
1262
  index_entry_free(entry);
1134
1263
  *entry_ptr = entry = existing;
1135
1264
  }
@@ -1139,6 +1268,10 @@ static int index_insert(
1139
1268
  * check for dups, this is actually cheaper in the long run.)
1140
1269
  */
1141
1270
  error = git_vector_insert_sorted(&index->entries, entry, index_no_dups);
1271
+
1272
+ if (error == 0) {
1273
+ INSERT_IN_MAP(index, entry, error);
1274
+ }
1142
1275
  }
1143
1276
 
1144
1277
  if (error < 0) {
@@ -1205,7 +1338,7 @@ int git_index_add_frombuffer(
1205
1338
  return -1;
1206
1339
  }
1207
1340
 
1208
- if (index_entry_dup(&entry, INDEX_OWNER(index), source_entry) < 0)
1341
+ if (index_entry_dup(&entry, index, source_entry) < 0)
1209
1342
  return -1;
1210
1343
 
1211
1344
  error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
@@ -1217,7 +1350,7 @@ int git_index_add_frombuffer(
1217
1350
  git_oid_cpy(&entry->id, &id);
1218
1351
  entry->file_size = len;
1219
1352
 
1220
- if ((error = index_insert(index, &entry, 1, true)) < 0)
1353
+ if ((error = index_insert(index, &entry, 1, true, true)) < 0)
1221
1354
  return error;
1222
1355
 
1223
1356
  /* Adding implies conflict was resolved, move conflict entries to REUC */
@@ -1276,7 +1409,7 @@ int git_index_add_bypath(git_index *index, const char *path)
1276
1409
  assert(index && path);
1277
1410
 
1278
1411
  if ((ret = index_entry_init(&entry, index, path)) == 0)
1279
- ret = index_insert(index, &entry, 1, false);
1412
+ ret = index_insert(index, &entry, 1, false, false);
1280
1413
 
1281
1414
  /* If we were given a directory, let's see if it's a submodule */
1282
1415
  if (ret < 0 && ret != GIT_EDIRECTORY)
@@ -1286,13 +1419,13 @@ int git_index_add_bypath(git_index *index, const char *path)
1286
1419
  git_submodule *sm;
1287
1420
  git_error_state err;
1288
1421
 
1289
- giterr_capture(&err, ret);
1422
+ giterr_state_capture(&err, ret);
1290
1423
 
1291
1424
  ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
1292
1425
  if (ret == GIT_ENOTFOUND)
1293
- return giterr_restore(&err);
1426
+ return giterr_state_restore(&err);
1294
1427
 
1295
- git__free(err.error_msg.message);
1428
+ giterr_state_free(&err);
1296
1429
 
1297
1430
  /*
1298
1431
  * EEXISTS means that there is a repository at that path, but it's not known
@@ -1302,7 +1435,7 @@ int git_index_add_bypath(git_index *index, const char *path)
1302
1435
  if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
1303
1436
  return ret;
1304
1437
 
1305
- if ((ret = index_insert(index, &entry, 1, false)) < 0)
1438
+ if ((ret = index_insert(index, &entry, 1, false, false)) < 0)
1306
1439
  return ret;
1307
1440
  } else if (ret < 0) {
1308
1441
  return ret;
@@ -1352,8 +1485,8 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
1352
1485
  return -1;
1353
1486
  }
1354
1487
 
1355
- if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 ||
1356
- (ret = index_insert(index, &entry, 1, true)) < 0)
1488
+ if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
1489
+ (ret = index_insert(index, &entry, 1, true, true)) < 0)
1357
1490
  return ret;
1358
1491
 
1359
1492
  git_tree_cache_invalidate_path(index->tree, entry->path);
@@ -1364,12 +1497,18 @@ int git_index_remove(git_index *index, const char *path, int stage)
1364
1497
  {
1365
1498
  int error;
1366
1499
  size_t position;
1500
+ git_index_entry remove_key = {{ 0 }};
1367
1501
 
1368
1502
  if (git_mutex_lock(&index->lock) < 0) {
1369
1503
  giterr_set(GITERR_OS, "Failed to lock index");
1370
1504
  return -1;
1371
1505
  }
1372
1506
 
1507
+ remove_key.path = path;
1508
+ GIT_IDXENTRY_STAGE_SET(&remove_key, stage);
1509
+
1510
+ DELETE_IN_MAP(index, &remove_key);
1511
+
1373
1512
  if (index_find(&position, index, path, 0, stage, false) < 0) {
1374
1513
  giterr_set(
1375
1514
  GITERR_INDEX, "Index does not contain %s at stage %d", path, stage);
@@ -1419,6 +1558,30 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
1419
1558
  return error;
1420
1559
  }
1421
1560
 
1561
+ int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
1562
+ {
1563
+ int error = 0;
1564
+ size_t pos;
1565
+ const git_index_entry *entry;
1566
+
1567
+ if (git_mutex_lock(&index->lock) < 0) {
1568
+ giterr_set(GITERR_OS, "Failed to lock index");
1569
+ return -1;
1570
+ }
1571
+
1572
+ index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY, false);
1573
+ entry = git_vector_get(&index->entries, pos);
1574
+ if (!entry || git__prefixcmp(entry->path, prefix) != 0)
1575
+ error = GIT_ENOTFOUND;
1576
+
1577
+ if (!error && at_pos)
1578
+ *at_pos = pos;
1579
+
1580
+ git_mutex_unlock(&index->lock);
1581
+
1582
+ return error;
1583
+ }
1584
+
1422
1585
  int git_index__find_pos(
1423
1586
  size_t *out, git_index *index, const char *path, size_t path_len, int stage)
1424
1587
  {
@@ -1472,9 +1635,9 @@ int git_index_conflict_add(git_index *index,
1472
1635
 
1473
1636
  assert (index);
1474
1637
 
1475
- if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 ||
1476
- (ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 ||
1477
- (ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
1638
+ if ((ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0 ||
1639
+ (ret = index_entry_dup(&entries[1], index, our_entry)) < 0 ||
1640
+ (ret = index_entry_dup(&entries[2], index, their_entry)) < 0)
1478
1641
  goto on_error;
1479
1642
 
1480
1643
  /* Validate entries */
@@ -1508,7 +1671,7 @@ int git_index_conflict_add(git_index *index,
1508
1671
  /* Make sure stage is correct */
1509
1672
  GIT_IDXENTRY_STAGE_SET(entries[i], i + 1);
1510
1673
 
1511
- if ((ret = index_insert(index, &entries[i], 0, true)) < 0)
1674
+ if ((ret = index_insert(index, &entries[i], 0, true, true)) < 0)
1512
1675
  goto on_error;
1513
1676
 
1514
1677
  entries[i] = NULL; /* don't free if later entry fails */
@@ -2082,7 +2245,7 @@ static size_t read_entry(
2082
2245
 
2083
2246
  entry.path = (char *)path_ptr;
2084
2247
 
2085
- if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0)
2248
+ if (index_entry_dup(out, index, &entry) < 0)
2086
2249
  return 0;
2087
2250
 
2088
2251
  return entry_size;
@@ -2180,6 +2343,11 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2180
2343
 
2181
2344
  assert(!index->entries.length);
2182
2345
 
2346
+ if (index->ignore_case)
2347
+ kh_resize(idxicase, (khash_t(idxicase) *) index->entries_map, header.entry_count);
2348
+ else
2349
+ kh_resize(idx, index->entries_map, header.entry_count);
2350
+
2183
2351
  /* Parse all the entries */
2184
2352
  for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
2185
2353
  git_index_entry *entry;
@@ -2196,6 +2364,13 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2196
2364
  goto done;
2197
2365
  }
2198
2366
 
2367
+ INSERT_IN_MAP(index, entry, error);
2368
+
2369
+ if (error < 0) {
2370
+ index_entry_free(entry);
2371
+ goto done;
2372
+ }
2373
+
2199
2374
  seek_forward(entry_size);
2200
2375
  }
2201
2376
 
@@ -2587,7 +2762,7 @@ static int read_tree_cb(
2587
2762
  entry->mode == old_entry->mode &&
2588
2763
  git_oid_equal(&entry->id, &old_entry->id))
2589
2764
  {
2590
- index_entry_cpy(entry, old_entry);
2765
+ index_entry_cpy(entry, data->index, old_entry, false);
2591
2766
  entry->flags_extended = 0;
2592
2767
  }
2593
2768
 
@@ -2610,7 +2785,13 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
2610
2785
  {
2611
2786
  int error = 0;
2612
2787
  git_vector entries = GIT_VECTOR_INIT;
2788
+ git_idxmap *entries_map;
2613
2789
  read_tree_data data;
2790
+ size_t i;
2791
+ git_index_entry *e;
2792
+
2793
+ if (git_idxmap_alloc(&entries_map) < 0)
2794
+ return -1;
2614
2795
 
2615
2796
  git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
2616
2797
 
@@ -2625,23 +2806,41 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
2625
2806
  if (index_sort_if_needed(index, true) < 0)
2626
2807
  return -1;
2627
2808
 
2628
- error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data);
2809
+ if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
2810
+ goto cleanup;
2629
2811
 
2630
- if (!error) {
2631
- git_vector_sort(&entries);
2812
+ if (index->ignore_case)
2813
+ kh_resize(idxicase, (khash_t(idxicase) *) entries_map, entries.length);
2814
+ else
2815
+ kh_resize(idx, entries_map, entries.length);
2632
2816
 
2633
- if ((error = git_index_clear(index)) < 0)
2634
- /* well, this isn't good */;
2635
- else if (git_mutex_lock(&index->lock) < 0) {
2636
- giterr_set(GITERR_OS, "Unable to acquire index lock");
2637
- error = -1;
2638
- } else {
2639
- git_vector_swap(&entries, &index->entries);
2640
- git_mutex_unlock(&index->lock);
2817
+ git_vector_foreach(&entries, i, e) {
2818
+ INSERT_IN_MAP_EX(index, entries_map, e, error);
2819
+
2820
+ if (error < 0) {
2821
+ giterr_set(GITERR_INDEX, "failed to insert entry into map");
2822
+ return error;
2641
2823
  }
2642
2824
  }
2643
2825
 
2826
+ error = 0;
2827
+
2828
+ git_vector_sort(&entries);
2829
+
2830
+ if ((error = git_index_clear(index)) < 0)
2831
+ /* well, this isn't good */;
2832
+ else if (git_mutex_lock(&index->lock) < 0) {
2833
+ giterr_set(GITERR_OS, "Unable to acquire index lock");
2834
+ error = -1;
2835
+ } else {
2836
+ git_vector_swap(&entries, &index->entries);
2837
+ entries_map = git__swap(index->entries_map, entries_map);
2838
+ git_mutex_unlock(&index->lock);
2839
+ }
2840
+
2841
+ cleanup:
2644
2842
  git_vector_free(&entries);
2843
+ git_idxmap_free(entries_map);
2645
2844
  if (error < 0)
2646
2845
  return error;
2647
2846
 
@@ -2658,6 +2857,7 @@ int git_index_read_index(
2658
2857
  remove_entries = GIT_VECTOR_INIT;
2659
2858
  git_iterator *index_iterator = NULL;
2660
2859
  git_iterator *new_iterator = NULL;
2860
+ git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
2661
2861
  const git_index_entry *old_entry, *new_entry;
2662
2862
  git_index_entry *entry;
2663
2863
  size_t i;
@@ -2667,10 +2867,10 @@ int git_index_read_index(
2667
2867
  (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0)
2668
2868
  goto done;
2669
2869
 
2670
- if ((error = git_iterator_for_index(&index_iterator,
2671
- index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2672
- (error = git_iterator_for_index(&new_iterator,
2673
- (git_index *)new_index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
2870
+ opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
2871
+
2872
+ if ((error = git_iterator_for_index(&index_iterator, index, &opts)) < 0 ||
2873
+ (error = git_iterator_for_index(&new_iterator, (git_index *)new_index, &opts)) < 0)
2674
2874
  goto done;
2675
2875
 
2676
2876
  if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
@@ -2694,7 +2894,7 @@ int git_index_read_index(
2694
2894
  if (diff < 0) {
2695
2895
  git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
2696
2896
  } else if (diff > 0) {
2697
- if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2897
+ if ((error = index_entry_dup(&entry, index, new_entry)) < 0)
2698
2898
  goto done;
2699
2899
 
2700
2900
  git_vector_insert(&new_entries, entry);
@@ -2705,7 +2905,7 @@ int git_index_read_index(
2705
2905
  if (git_oid_equal(&old_entry->id, &new_entry->id)) {
2706
2906
  git_vector_insert(&new_entries, (git_index_entry *)old_entry);
2707
2907
  } else {
2708
- if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2908
+ if ((error = index_entry_dup(&entry, index, new_entry)) < 0)
2709
2909
  goto done;
2710
2910
 
2711
2911
  git_vector_insert(&new_entries, entry);