rugged 0.23.0b2 → 0.23.0b4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -0,0 +1,257 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #ifdef GIT_CURL
9
+
10
+ #include <curl/curl.h>
11
+
12
+ #include "stream.h"
13
+ #include "git2/transport.h"
14
+ #include "buffer.h"
15
+ #include "vector.h"
16
+
17
+ typedef struct {
18
+ git_stream parent;
19
+ CURL *handle;
20
+ curl_socket_t socket;
21
+ char curl_error[CURL_ERROR_SIZE + 1];
22
+ git_cert_x509 cert_info;
23
+ git_strarray cert_info_strings;
24
+ } curl_stream;
25
+
26
+ static int seterr_curl(curl_stream *s)
27
+ {
28
+ giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
29
+ return -1;
30
+ }
31
+
32
+ static int curls_connect(git_stream *stream)
33
+ {
34
+ curl_stream *s = (curl_stream *) stream;
35
+ long sockextr;
36
+ int failed_cert = 0;
37
+ CURLcode res;
38
+ res = curl_easy_perform(s->handle);
39
+
40
+ if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION)
41
+ return seterr_curl(s);
42
+ if (res == CURLE_PEER_FAILED_VERIFICATION)
43
+ failed_cert = 1;
44
+
45
+ if ((res = curl_easy_getinfo(s->handle, CURLINFO_LASTSOCKET, &sockextr)) != CURLE_OK)
46
+ return seterr_curl(s);
47
+
48
+ s->socket = sockextr;
49
+
50
+ if (s->parent.encrypted && failed_cert)
51
+ return GIT_ECERTIFICATE;
52
+
53
+ return 0;
54
+ }
55
+
56
+ static int curls_certificate(git_cert **out, git_stream *stream)
57
+ {
58
+ int error;
59
+ CURLcode res;
60
+ struct curl_slist *slist;
61
+ struct curl_certinfo *certinfo;
62
+ git_vector strings = GIT_VECTOR_INIT;
63
+ curl_stream *s = (curl_stream *) stream;
64
+
65
+ if ((res = curl_easy_getinfo(s->handle, CURLINFO_CERTINFO, &certinfo)) != CURLE_OK)
66
+ return seterr_curl(s);
67
+
68
+ /* No information is available, can happen with SecureTransport */
69
+ if (certinfo->num_of_certs == 0) {
70
+ s->cert_info.cert_type = GIT_CERT_NONE;
71
+ s->cert_info.data = NULL;
72
+ s->cert_info.len = 0;
73
+ return 0;
74
+ }
75
+
76
+ if ((error = git_vector_init(&strings, 8, NULL)) < 0)
77
+ return error;
78
+
79
+ for (slist = certinfo->certinfo[0]; slist; slist = slist->next) {
80
+ char *str = git__strdup(slist->data);
81
+ GITERR_CHECK_ALLOC(str);
82
+ }
83
+
84
+ /* Copy the contents of the vector into a strarray so we can expose them */
85
+ s->cert_info_strings.strings = (char **) strings.contents;
86
+ s->cert_info_strings.count = strings.length;
87
+
88
+ s->cert_info.cert_type = GIT_CERT_STRARRAY;
89
+ s->cert_info.data = &s->cert_info_strings;
90
+ s->cert_info.len = strings.length;
91
+
92
+ *out = (git_cert *) &s->cert_info;
93
+
94
+ return 0;
95
+ }
96
+
97
+ static int curls_set_proxy(git_stream *stream, const char *proxy_url)
98
+ {
99
+ CURLcode res;
100
+ curl_stream *s = (curl_stream *) stream;
101
+
102
+ if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, proxy_url)) != CURLE_OK)
103
+ return seterr_curl(s);
104
+
105
+ return 0;
106
+ }
107
+
108
+ static int wait_for(curl_socket_t fd, bool reading)
109
+ {
110
+ int ret;
111
+ fd_set infd, outfd, errfd;
112
+
113
+ FD_ZERO(&infd);
114
+ FD_ZERO(&outfd);
115
+ FD_ZERO(&errfd);
116
+
117
+ FD_SET(fd, &errfd);
118
+ if (reading)
119
+ FD_SET(fd, &infd);
120
+ else
121
+ FD_SET(fd, &outfd);
122
+
123
+ if ((ret = select(fd + 1, &infd, &outfd, &errfd, NULL)) < 0) {
124
+ giterr_set(GITERR_OS, "error in select");
125
+ return -1;
126
+ }
127
+
128
+ return 0;
129
+ }
130
+
131
+ static ssize_t curls_write(git_stream *stream, const char *data, size_t len, int flags)
132
+ {
133
+ int error;
134
+ size_t off = 0, sent;
135
+ CURLcode res;
136
+ curl_stream *s = (curl_stream *) stream;
137
+
138
+ GIT_UNUSED(flags);
139
+
140
+ do {
141
+ if ((error = wait_for(s->socket, false)) < 0)
142
+ return error;
143
+
144
+ res = curl_easy_send(s->handle, data + off, len - off, &sent);
145
+ if (res == CURLE_OK)
146
+ off += sent;
147
+ } while ((res == CURLE_OK || res == CURLE_AGAIN) && off < len);
148
+
149
+ if (res != CURLE_OK)
150
+ return seterr_curl(s);
151
+
152
+ return len;
153
+ }
154
+
155
+ static ssize_t curls_read(git_stream *stream, void *data, size_t len)
156
+ {
157
+ int error;
158
+ size_t read;
159
+ CURLcode res;
160
+ curl_stream *s = (curl_stream *) stream;
161
+
162
+ do {
163
+ if ((error = wait_for(s->socket, true)) < 0)
164
+ return error;
165
+
166
+ res = curl_easy_recv(s->handle, data, len, &read);
167
+ } while (res == CURLE_AGAIN);
168
+
169
+ if (res != CURLE_OK)
170
+ return seterr_curl(s);
171
+
172
+ return read;
173
+ }
174
+
175
+ static int curls_close(git_stream *stream)
176
+ {
177
+ curl_stream *s = (curl_stream *) stream;
178
+
179
+ if (!s->handle)
180
+ return 0;
181
+
182
+ curl_easy_cleanup(s->handle);
183
+ s->handle = NULL;
184
+ s->socket = 0;
185
+
186
+ return 0;
187
+ }
188
+
189
+ static void curls_free(git_stream *stream)
190
+ {
191
+ curl_stream *s = (curl_stream *) stream;
192
+
193
+ curls_close(stream);
194
+ git_strarray_free(&s->cert_info_strings);
195
+ git__free(s);
196
+ }
197
+
198
+ int git_curl_stream_new(git_stream **out, const char *host, const char *port)
199
+ {
200
+ curl_stream *st;
201
+ CURL *handle;
202
+ int iport = 0, error;
203
+
204
+ st = git__calloc(1, sizeof(curl_stream));
205
+ GITERR_CHECK_ALLOC(st);
206
+
207
+ handle = curl_easy_init();
208
+ if (handle == NULL) {
209
+ giterr_set(GITERR_NET, "failed to create curl handle");
210
+ return -1;
211
+ }
212
+
213
+ if ((error = git__strtol32(&iport, port, NULL, 10)) < 0)
214
+ return error;
215
+
216
+ curl_easy_setopt(handle, CURLOPT_URL, host);
217
+ curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
218
+ curl_easy_setopt(handle, CURLOPT_PORT, iport);
219
+ curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
220
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
221
+ curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
222
+ curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
223
+
224
+ /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */
225
+
226
+ st->parent.version = GIT_STREAM_VERSION;
227
+ st->parent.encrypted = 0; /* we don't encrypt ourselves */
228
+ st->parent.proxy_support = 1;
229
+ st->parent.connect = curls_connect;
230
+ st->parent.certificate = curls_certificate;
231
+ st->parent.set_proxy = curls_set_proxy;
232
+ st->parent.read = curls_read;
233
+ st->parent.write = curls_write;
234
+ st->parent.close = curls_close;
235
+ st->parent.free = curls_free;
236
+ st->handle = handle;
237
+
238
+ *out = (git_stream *) st;
239
+ return 0;
240
+ }
241
+
242
+ #else
243
+
244
+ #include "stream.h"
245
+
246
+ int git_curl_stream_new(git_stream **out, const char *host, const char *port)
247
+ {
248
+ GIT_UNUSED(out);
249
+ GIT_UNUSED(host);
250
+ GIT_UNUSED(port);
251
+
252
+ giterr_set(GITERR_NET, "curl is not supported in this version");
253
+ return -1;
254
+ }
255
+
256
+
257
+ #endif
@@ -0,0 +1,14 @@
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_curl_stream_h__
8
+ #define INCLUDE_curl_stream_h__
9
+
10
+ #include "git2/sys/stream.h"
11
+
12
+ extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
13
+
14
+ #endif
@@ -77,11 +77,24 @@ static int diff_insert_delta(
77
77
  static int diff_delta__from_one(
78
78
  git_diff *diff,
79
79
  git_delta_t status,
80
- const git_index_entry *entry)
80
+ const git_index_entry *oitem,
81
+ const git_index_entry *nitem)
81
82
  {
83
+ const git_index_entry *entry = nitem;
84
+ bool has_old = false;
82
85
  git_diff_delta *delta;
83
86
  const char *matched_pathspec;
84
87
 
88
+ assert((oitem != NULL) ^ (nitem != NULL));
89
+
90
+ if (oitem) {
91
+ entry = oitem;
92
+ has_old = true;
93
+ }
94
+
95
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE))
96
+ has_old = !has_old;
97
+
85
98
  if ((entry->flags & GIT_IDXENTRY_VALID) != 0)
86
99
  return 0;
87
100
 
@@ -111,20 +124,21 @@ static int diff_delta__from_one(
111
124
  assert(status != GIT_DELTA_MODIFIED);
112
125
  delta->nfiles = 1;
113
126
 
114
- if (delta->status == GIT_DELTA_DELETED) {
127
+ if (has_old) {
115
128
  delta->old_file.mode = entry->mode;
116
129
  delta->old_file.size = entry->file_size;
130
+ delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS;
117
131
  git_oid_cpy(&delta->old_file.id, &entry->id);
118
132
  } else /* ADDED, IGNORED, UNTRACKED */ {
119
133
  delta->new_file.mode = entry->mode;
120
134
  delta->new_file.size = entry->file_size;
135
+ delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS;
121
136
  git_oid_cpy(&delta->new_file.id, &entry->id);
122
137
  }
123
138
 
124
139
  delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
125
140
 
126
- if (delta->status == GIT_DELTA_DELETED ||
127
- !git_oid_iszero(&delta->new_file.id))
141
+ if (has_old || !git_oid_iszero(&delta->new_file.id))
128
142
  delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
129
143
 
130
144
  return diff_insert_delta(diff, delta, matched_pathspec);
@@ -137,9 +151,10 @@ static int diff_delta__from_two(
137
151
  uint32_t old_mode,
138
152
  const git_index_entry *new_entry,
139
153
  uint32_t new_mode,
140
- git_oid *new_oid,
154
+ const git_oid *new_id,
141
155
  const char *matched_pathspec)
142
156
  {
157
+ const git_oid *old_id = &old_entry->id;
143
158
  git_diff_delta *delta;
144
159
  const char *canonical_path = old_entry->path;
145
160
 
@@ -147,38 +162,45 @@ static int diff_delta__from_two(
147
162
  DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED))
148
163
  return 0;
149
164
 
165
+ if (!new_id)
166
+ new_id = &new_entry->id;
167
+
150
168
  if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
151
169
  uint32_t temp_mode = old_mode;
152
170
  const git_index_entry *temp_entry = old_entry;
171
+ const git_oid *temp_id = old_id;
172
+
153
173
  old_entry = new_entry;
154
174
  new_entry = temp_entry;
155
175
  old_mode = new_mode;
156
176
  new_mode = temp_mode;
177
+ old_id = new_id;
178
+ new_id = temp_id;
157
179
  }
158
180
 
159
181
  delta = diff_delta__alloc(diff, status, canonical_path);
160
182
  GITERR_CHECK_ALLOC(delta);
161
183
  delta->nfiles = 2;
162
184
 
163
- git_oid_cpy(&delta->old_file.id, &old_entry->id);
164
- delta->old_file.size = old_entry->file_size;
165
- delta->old_file.mode = old_mode;
166
- delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
185
+ if (!git_index_entry_is_conflict(old_entry)) {
186
+ delta->old_file.size = old_entry->file_size;
187
+ delta->old_file.mode = old_mode;
188
+ git_oid_cpy(&delta->old_file.id, old_id);
189
+ delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID |
190
+ GIT_DIFF_FLAG_EXISTS;
191
+ }
167
192
 
168
- git_oid_cpy(&delta->new_file.id, &new_entry->id);
169
- delta->new_file.size = new_entry->file_size;
170
- delta->new_file.mode = new_mode;
193
+ if (!git_index_entry_is_conflict(new_entry)) {
194
+ git_oid_cpy(&delta->new_file.id, new_id);
195
+ delta->new_file.size = new_entry->file_size;
196
+ delta->new_file.mode = new_mode;
197
+ delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS;
198
+ delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS;
171
199
 
172
- if (new_oid) {
173
- if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE))
174
- git_oid_cpy(&delta->old_file.id, new_oid);
175
- else
176
- git_oid_cpy(&delta->new_file.id, new_oid);
200
+ if (!git_oid_iszero(&new_entry->id))
201
+ delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
177
202
  }
178
203
 
179
- if (new_oid || !git_oid_iszero(&new_entry->id))
180
- delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
181
-
182
204
  return diff_insert_delta(diff, delta, matched_pathspec);
183
205
  }
184
206
 
@@ -327,6 +349,22 @@ static const char *diff_mnemonic_prefix(
327
349
  return pfx;
328
350
  }
329
351
 
352
+ static int diff_entry_cmp(const void *a, const void *b)
353
+ {
354
+ const git_index_entry *entry_a = a;
355
+ const git_index_entry *entry_b = b;
356
+
357
+ return strcmp(entry_a->path, entry_b->path);
358
+ }
359
+
360
+ static int diff_entry_icmp(const void *a, const void *b)
361
+ {
362
+ const git_index_entry *entry_a = a;
363
+ const git_index_entry *entry_b = b;
364
+
365
+ return strcasecmp(entry_a->path, entry_b->path);
366
+ }
367
+
330
368
  static void diff_set_ignore_case(git_diff *diff, bool ignore_case)
331
369
  {
332
370
  if (!ignore_case) {
@@ -335,7 +373,7 @@ static void diff_set_ignore_case(git_diff *diff, bool ignore_case)
335
373
  diff->strcomp = git__strcmp;
336
374
  diff->strncomp = git__strncmp;
337
375
  diff->pfxcomp = git__prefixcmp;
338
- diff->entrycomp = git_index_entry_cmp;
376
+ diff->entrycomp = diff_entry_cmp;
339
377
 
340
378
  git_vector_set_cmp(&diff->deltas, git_diff_delta__cmp);
341
379
  } else {
@@ -344,7 +382,7 @@ static void diff_set_ignore_case(git_diff *diff, bool ignore_case)
344
382
  diff->strcomp = git__strcasecmp;
345
383
  diff->strncomp = git__strncasecmp;
346
384
  diff->pfxcomp = git__prefixcmp_icase;
347
- diff->entrycomp = git_index_entry_icmp;
385
+ diff->entrycomp = diff_entry_icmp;
348
386
 
349
387
  git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);
350
388
  }
@@ -532,7 +570,7 @@ int git_diff__oid_for_file(
532
570
  git_oid *out,
533
571
  git_diff *diff,
534
572
  const char *path,
535
- uint16_t mode,
573
+ uint16_t mode,
536
574
  git_off_t size)
537
575
  {
538
576
  git_index_entry entry;
@@ -542,13 +580,14 @@ int git_diff__oid_for_file(
542
580
  entry.file_size = size;
543
581
  entry.path = (char *)path;
544
582
 
545
- return git_diff__oid_for_entry(out, diff, &entry, NULL);
583
+ return git_diff__oid_for_entry(out, diff, &entry, mode, NULL);
546
584
  }
547
585
 
548
586
  int git_diff__oid_for_entry(
549
587
  git_oid *out,
550
588
  git_diff *diff,
551
589
  const git_index_entry *src,
590
+ uint16_t mode,
552
591
  const git_oid *update_match)
553
592
  {
554
593
  int error = 0;
@@ -562,7 +601,7 @@ int git_diff__oid_for_entry(
562
601
  &full_path, git_repository_workdir(diff->repo), entry.path) < 0)
563
602
  return -1;
564
603
 
565
- if (!entry.mode) {
604
+ if (!mode) {
566
605
  struct stat st;
567
606
 
568
607
  diff->perf.stat_calls++;
@@ -578,7 +617,7 @@ int git_diff__oid_for_entry(
578
617
  }
579
618
 
580
619
  /* calculate OID for file if possible */
581
- if (S_ISGITLINK(entry.mode)) {
620
+ if (S_ISGITLINK(mode)) {
582
621
  git_submodule *sm;
583
622
 
584
623
  if (!git_submodule_lookup(&sm, diff->repo, entry.path)) {
@@ -592,7 +631,7 @@ int git_diff__oid_for_entry(
592
631
  */
593
632
  giterr_clear();
594
633
  }
595
- } else if (S_ISLNK(entry.mode)) {
634
+ } else if (S_ISLNK(mode)) {
596
635
  error = git_odb__hashlink(out, full_path.ptr);
597
636
  diff->perf.oid_calculations++;
598
637
  } else if (!git__is_sizet(entry.file_size)) {
@@ -619,10 +658,15 @@ int git_diff__oid_for_entry(
619
658
  /* update index for entry if requested */
620
659
  if (!error && update_match && git_oid_equal(out, update_match)) {
621
660
  git_index *idx;
661
+ git_index_entry updated_entry;
662
+
663
+ memcpy(&updated_entry, &entry, sizeof(git_index_entry));
664
+ updated_entry.mode = mode;
665
+ git_oid_cpy(&updated_entry.id, out);
622
666
 
623
667
  if (!(error = git_repository_index__weakptr(&idx, diff->repo))) {
624
- git_oid_cpy(&entry.id, out);
625
- error = git_index_add(idx, &entry);
668
+ error = git_index_add(idx, &updated_entry);
669
+ diff->index_updated = true;
626
670
  }
627
671
  }
628
672
 
@@ -731,47 +775,54 @@ static int maybe_modified(
731
775
  new_is_workdir)
732
776
  nmode = (nmode & ~MODE_BITS_MASK) | (omode & MODE_BITS_MASK);
733
777
 
778
+ /* if one side is a conflict, mark the whole delta as conflicted */
779
+ if (git_index_entry_is_conflict(oitem) ||
780
+ git_index_entry_is_conflict(nitem)) {
781
+ status = GIT_DELTA_CONFLICTED;
782
+
734
783
  /* support "assume unchanged" (poorly, b/c we still stat everything) */
735
- if ((oitem->flags & GIT_IDXENTRY_VALID) != 0)
784
+ } else if ((oitem->flags & GIT_IDXENTRY_VALID) != 0) {
736
785
  status = GIT_DELTA_UNMODIFIED;
737
786
 
738
787
  /* support "skip worktree" index bit */
739
- else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
788
+ } else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0) {
740
789
  status = GIT_DELTA_UNMODIFIED;
741
790
 
742
791
  /* if basic type of file changed, then split into delete and add */
743
- else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
744
- if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE))
792
+ } else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
793
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE)) {
745
794
  status = GIT_DELTA_TYPECHANGE;
795
+ }
796
+
746
797
  else if (nmode == GIT_FILEMODE_UNREADABLE) {
747
- if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem)))
748
- error = diff_delta__from_one(diff, GIT_DELTA_UNREADABLE, nitem);
798
+ if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem, NULL)))
799
+ error = diff_delta__from_one(diff, GIT_DELTA_UNREADABLE, NULL, nitem);
749
800
  return error;
750
801
  }
802
+
751
803
  else {
752
- if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem)))
753
- error = diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem);
804
+ if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem, NULL)))
805
+ error = diff_delta__from_one(diff, GIT_DELTA_ADDED, NULL, nitem);
754
806
  return error;
755
807
  }
756
- }
757
808
 
758
809
  /* if oids and modes match (and are valid), then file is unmodified */
759
- else if (git_oid_equal(&oitem->id, &nitem->id) &&
810
+ } else if (git_oid_equal(&oitem->id, &nitem->id) &&
760
811
  omode == nmode &&
761
- !git_oid_iszero(&oitem->id))
812
+ !git_oid_iszero(&oitem->id)) {
762
813
  status = GIT_DELTA_UNMODIFIED;
763
814
 
764
815
  /* if we have an unknown OID and a workdir iterator, then check some
765
816
  * circumstances that can accelerate things or need special handling
766
817
  */
767
- else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
818
+ } else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
768
819
  bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0);
769
820
  bool use_nanos = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_NANOSECS) != 0);
821
+ git_index *index;
822
+ git_iterator_index(&index, info->new_iter);
770
823
 
771
824
  status = GIT_DELTA_UNMODIFIED;
772
825
 
773
- /* TODO: add check against index file st_mtime to avoid racy-git */
774
-
775
826
  if (S_ISGITLINK(nmode)) {
776
827
  if ((error = maybe_modified_submodule(&status, &noid, diff, info)) < 0)
777
828
  return error;
@@ -790,17 +841,18 @@ static int maybe_modified(
790
841
  !diff_time_eq(&oitem->ctime, &nitem->ctime, use_nanos)) ||
791
842
  oitem->ino != nitem->ino ||
792
843
  oitem->uid != nitem->uid ||
793
- oitem->gid != nitem->gid)
844
+ oitem->gid != nitem->gid ||
845
+ (index && nitem->mtime.seconds >= index->stamp.mtime))
794
846
  {
795
847
  status = GIT_DELTA_MODIFIED;
796
848
  modified_uncertain = true;
797
849
  }
798
- }
799
850
 
800
851
  /* if mode is GITLINK and submodules are ignored, then skip */
801
- else if (S_ISGITLINK(nmode) &&
802
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
852
+ } else if (S_ISGITLINK(nmode) &&
853
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES)) {
803
854
  status = GIT_DELTA_UNMODIFIED;
855
+ }
804
856
 
805
857
  /* if we got here and decided that the files are modified, but we
806
858
  * haven't calculated the OID of the new item, then calculate it now
@@ -809,8 +861,9 @@ static int maybe_modified(
809
861
  const git_oid *update_check =
810
862
  DIFF_FLAG_IS_SET(diff, GIT_DIFF_UPDATE_INDEX) && omode == nmode ?
811
863
  &oitem->id : NULL;
864
+
812
865
  if ((error = git_diff__oid_for_entry(
813
- &noid, diff, nitem, update_check)) < 0)
866
+ &noid, diff, nitem, nmode, update_check)) < 0)
814
867
  return error;
815
868
 
816
869
  /* if oid matches, then mark unmodified (except submodules, where
@@ -830,8 +883,9 @@ static int maybe_modified(
830
883
  DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_CASECHANGE) &&
831
884
  strcmp(oitem->path, nitem->path) != 0) {
832
885
 
833
- if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem)))
834
- error = diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem);
886
+ if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem, NULL)))
887
+ error = diff_delta__from_one(diff, GIT_DELTA_ADDED, NULL, nitem);
888
+
835
889
  return error;
836
890
  }
837
891
 
@@ -857,6 +911,84 @@ static bool entry_is_prefixed(
857
911
  item->path[pathlen] == '/');
858
912
  }
859
913
 
914
+ static int iterator_current(
915
+ const git_index_entry **entry,
916
+ git_iterator *iterator)
917
+ {
918
+ int error;
919
+
920
+ if ((error = git_iterator_current(entry, iterator)) == GIT_ITEROVER) {
921
+ *entry = NULL;
922
+ error = 0;
923
+ }
924
+
925
+ return error;
926
+ }
927
+
928
+ static int iterator_advance(
929
+ const git_index_entry **entry,
930
+ git_iterator *iterator)
931
+ {
932
+ const git_index_entry *prev_entry = *entry;
933
+ int cmp, error;
934
+
935
+ /* if we're looking for conflicts, we only want to report
936
+ * one conflict for each file, instead of all three sides.
937
+ * so if this entry is a conflict for this file, and the
938
+ * previous one was a conflict for the same file, skip it.
939
+ */
940
+ while ((error = git_iterator_advance(entry, iterator)) == 0) {
941
+ if (!(iterator->flags & GIT_ITERATOR_INCLUDE_CONFLICTS) ||
942
+ !git_index_entry_is_conflict(prev_entry) ||
943
+ !git_index_entry_is_conflict(*entry))
944
+ break;
945
+
946
+ cmp = (iterator->flags & GIT_ITERATOR_IGNORE_CASE) ?
947
+ strcasecmp(prev_entry->path, (*entry)->path) :
948
+ strcmp(prev_entry->path, (*entry)->path);
949
+
950
+ if (cmp)
951
+ break;
952
+ }
953
+
954
+ if (error == GIT_ITEROVER) {
955
+ *entry = NULL;
956
+ error = 0;
957
+ }
958
+
959
+ return error;
960
+ }
961
+
962
+ static int iterator_advance_into(
963
+ const git_index_entry **entry,
964
+ git_iterator *iterator)
965
+ {
966
+ int error;
967
+
968
+ if ((error = git_iterator_advance_into(entry, iterator)) == GIT_ITEROVER) {
969
+ *entry = NULL;
970
+ error = 0;
971
+ }
972
+
973
+ return error;
974
+ }
975
+
976
+ static int iterator_advance_over_with_status(
977
+ const git_index_entry **entry,
978
+ git_iterator_status_t *status,
979
+ git_iterator *iterator)
980
+ {
981
+ int error;
982
+
983
+ if ((error = git_iterator_advance_over_with_status(
984
+ entry, status, iterator)) == GIT_ITEROVER) {
985
+ *entry = NULL;
986
+ error = 0;
987
+ }
988
+
989
+ return error;
990
+ }
991
+
860
992
  static int handle_unmatched_new_item(
861
993
  git_diff *diff, diff_in_progress *info)
862
994
  {
@@ -868,8 +1000,12 @@ static int handle_unmatched_new_item(
868
1000
  /* check if this is a prefix of the other side */
869
1001
  contains_oitem = entry_is_prefixed(diff, info->oitem, nitem);
870
1002
 
1003
+ /* update delta_type if this item is conflicted */
1004
+ if (git_index_entry_is_conflict(nitem))
1005
+ delta_type = GIT_DELTA_CONFLICTED;
1006
+
871
1007
  /* update delta_type if this item is ignored */
872
- if (git_iterator_current_is_ignored(info->new_iter))
1008
+ else if (git_iterator_current_is_ignored(info->new_iter))
873
1009
  delta_type = GIT_DELTA_IGNORED;
874
1010
 
875
1011
  if (nitem->mode == GIT_FILEMODE_TREE) {
@@ -904,18 +1040,17 @@ static int handle_unmatched_new_item(
904
1040
  git_iterator_status_t untracked_state;
905
1041
 
906
1042
  /* attempt to insert record for this directory */
907
- if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0)
1043
+ if ((error = diff_delta__from_one(diff, delta_type, NULL, nitem)) != 0)
908
1044
  return error;
909
1045
 
910
1046
  /* if delta wasn't created (because of rules), just skip ahead */
911
1047
  last = diff_delta__last_for_item(diff, nitem);
912
1048
  if (!last)
913
- return git_iterator_advance(&info->nitem, info->new_iter);
1049
+ return iterator_advance(&info->nitem, info->new_iter);
914
1050
 
915
1051
  /* iterate into dir looking for an actual untracked file */
916
- if ((error = git_iterator_advance_over_with_status(
917
- &info->nitem, &untracked_state, info->new_iter)) < 0 &&
918
- error != GIT_ITEROVER)
1052
+ if ((error = iterator_advance_over_with_status(
1053
+ &info->nitem, &untracked_state, info->new_iter)) < 0)
919
1054
  return error;
920
1055
 
921
1056
  /* if we found nothing or just ignored items, update the record */
@@ -935,7 +1070,7 @@ static int handle_unmatched_new_item(
935
1070
 
936
1071
  /* try to advance into directory if necessary */
937
1072
  if (recurse_into_dir) {
938
- error = git_iterator_advance_into(&info->nitem, info->new_iter);
1073
+ error = iterator_advance_into(&info->nitem, info->new_iter);
939
1074
 
940
1075
  /* if real error or no error, proceed with iteration */
941
1076
  if (error != GIT_ENOTFOUND)
@@ -946,7 +1081,7 @@ static int handle_unmatched_new_item(
946
1081
  * it or ignore it
947
1082
  */
948
1083
  if (contains_oitem)
949
- return git_iterator_advance(&info->nitem, info->new_iter);
1084
+ return iterator_advance(&info->nitem, info->new_iter);
950
1085
  delta_type = GIT_DELTA_IGNORED;
951
1086
  }
952
1087
  }
@@ -955,10 +1090,12 @@ static int handle_unmatched_new_item(
955
1090
  DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS) &&
956
1091
  git_iterator_current_tree_is_ignored(info->new_iter))
957
1092
  /* item contained in ignored directory, so skip over it */
958
- return git_iterator_advance(&info->nitem, info->new_iter);
1093
+ return iterator_advance(&info->nitem, info->new_iter);
959
1094
 
960
- else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR)
961
- delta_type = GIT_DELTA_ADDED;
1095
+ else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) {
1096
+ if (delta_type != GIT_DELTA_CONFLICTED)
1097
+ delta_type = GIT_DELTA_ADDED;
1098
+ }
962
1099
 
963
1100
  else if (nitem->mode == GIT_FILEMODE_COMMIT) {
964
1101
  /* ignore things that are not actual submodules */
@@ -968,12 +1105,12 @@ static int handle_unmatched_new_item(
968
1105
 
969
1106
  /* if this contains a tracked item, treat as normal TREE */
970
1107
  if (contains_oitem) {
971
- error = git_iterator_advance_into(&info->nitem, info->new_iter);
1108
+ error = iterator_advance_into(&info->nitem, info->new_iter);
972
1109
  if (error != GIT_ENOTFOUND)
973
1110
  return error;
974
1111
 
975
1112
  giterr_clear();
976
- return git_iterator_advance(&info->nitem, info->new_iter);
1113
+ return iterator_advance(&info->nitem, info->new_iter);
977
1114
  }
978
1115
  }
979
1116
  }
@@ -986,7 +1123,7 @@ static int handle_unmatched_new_item(
986
1123
  }
987
1124
 
988
1125
  /* Actually create the record for this item if necessary */
989
- if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0)
1126
+ if ((error = diff_delta__from_one(diff, delta_type, NULL, nitem)) != 0)
990
1127
  return error;
991
1128
 
992
1129
  /* If user requested TYPECHANGE records, then check for that instead of
@@ -1004,14 +1141,20 @@ static int handle_unmatched_new_item(
1004
1141
  }
1005
1142
  }
1006
1143
 
1007
- return git_iterator_advance(&info->nitem, info->new_iter);
1144
+ return iterator_advance(&info->nitem, info->new_iter);
1008
1145
  }
1009
1146
 
1010
1147
  static int handle_unmatched_old_item(
1011
1148
  git_diff *diff, diff_in_progress *info)
1012
1149
  {
1013
- int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem);
1014
- if (error != 0)
1150
+ git_delta_t delta_type = GIT_DELTA_DELETED;
1151
+ int error;
1152
+
1153
+ /* update delta_type if this item is conflicted */
1154
+ if (git_index_entry_is_conflict(info->oitem))
1155
+ delta_type = GIT_DELTA_CONFLICTED;
1156
+
1157
+ if ((error = diff_delta__from_one(diff, delta_type, info->oitem, NULL)) < 0)
1015
1158
  return error;
1016
1159
 
1017
1160
  /* if we are generating TYPECHANGE records then check for that
@@ -1033,10 +1176,10 @@ static int handle_unmatched_old_item(
1033
1176
  */
1034
1177
  if (S_ISDIR(info->nitem->mode) &&
1035
1178
  DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS))
1036
- return git_iterator_advance(&info->nitem, info->new_iter);
1179
+ return iterator_advance(&info->nitem, info->new_iter);
1037
1180
  }
1038
1181
 
1039
- return git_iterator_advance(&info->oitem, info->old_iter);
1182
+ return iterator_advance(&info->oitem, info->old_iter);
1040
1183
  }
1041
1184
 
1042
1185
  static int handle_matched_item(
@@ -1047,9 +1190,8 @@ static int handle_matched_item(
1047
1190
  if ((error = maybe_modified(diff, info)) < 0)
1048
1191
  return error;
1049
1192
 
1050
- if (!(error = git_iterator_advance(&info->oitem, info->old_iter)) ||
1051
- error == GIT_ITEROVER)
1052
- error = git_iterator_advance(&info->nitem, info->new_iter);
1193
+ if (!(error = iterator_advance(&info->oitem, info->old_iter)))
1194
+ error = iterator_advance(&info->nitem, info->new_iter);
1053
1195
 
1054
1196
  return error;
1055
1197
  }
@@ -1085,13 +1227,9 @@ int git_diff__from_iterators(
1085
1227
  if ((error = diff_list_apply_options(diff, opts)) < 0)
1086
1228
  goto cleanup;
1087
1229
 
1088
- if ((error = git_iterator_current(&info.oitem, old_iter)) < 0 &&
1089
- error != GIT_ITEROVER)
1230
+ if ((error = iterator_current(&info.oitem, old_iter)) < 0 ||
1231
+ (error = iterator_current(&info.nitem, new_iter)) < 0)
1090
1232
  goto cleanup;
1091
- if ((error = git_iterator_current(&info.nitem, new_iter)) < 0 &&
1092
- error != GIT_ITEROVER)
1093
- goto cleanup;
1094
- error = 0;
1095
1233
 
1096
1234
  /* run iterators building diffs */
1097
1235
  while (!error && (info.oitem || info.nitem)) {
@@ -1113,10 +1251,6 @@ int git_diff__from_iterators(
1113
1251
  */
1114
1252
  else
1115
1253
  error = handle_matched_item(diff, &info);
1116
-
1117
- /* because we are iterating over two lists, ignore ITEROVER */
1118
- if (error == GIT_ITEROVER)
1119
- error = 0;
1120
1254
  }
1121
1255
 
1122
1256
  diff->perf.stat_calls += old_iter->stat_calls + new_iter->stat_calls;
@@ -1186,6 +1320,8 @@ int git_diff_tree_to_index(
1186
1320
  {
1187
1321
  int error = 0;
1188
1322
  bool index_ignore_case = false;
1323
+ git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE |
1324
+ GIT_ITERATOR_INCLUDE_CONFLICTS;
1189
1325
 
1190
1326
  assert(diff && repo);
1191
1327
 
@@ -1195,10 +1331,8 @@ int git_diff_tree_to_index(
1195
1331
  index_ignore_case = index->ignore_case;
1196
1332
 
1197
1333
  DIFF_FROM_ITERATORS(
1198
- git_iterator_for_tree(
1199
- &a, old_tree, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx),
1200
- git_iterator_for_index(
1201
- &b, index, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx)
1334
+ git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx),
1335
+ git_iterator_for_index(&b, index, iflag, pfx, pfx)
1202
1336
  );
1203
1337
 
1204
1338
  /* if index is in case-insensitive order, re-sort deltas to match */
@@ -1222,12 +1356,13 @@ int git_diff_index_to_workdir(
1222
1356
  return error;
1223
1357
 
1224
1358
  DIFF_FROM_ITERATORS(
1225
- git_iterator_for_index(&a, index, 0, pfx, pfx),
1359
+ git_iterator_for_index(
1360
+ &a, index, GIT_ITERATOR_INCLUDE_CONFLICTS, pfx, pfx),
1226
1361
  git_iterator_for_workdir(
1227
1362
  &b, repo, index, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
1228
1363
  );
1229
1364
 
1230
- if (!error && DIFF_FLAG_IS_SET(*diff, GIT_DIFF_UPDATE_INDEX))
1365
+ if (!error && DIFF_FLAG_IS_SET(*diff, GIT_DIFF_UPDATE_INDEX) && (*diff)->index_updated)
1231
1366
  error = git_index_write(index);
1232
1367
 
1233
1368
  return error;