rugged 0.28.4.1 → 0.28.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,6 +13,7 @@
13
13
  #include "buffer.h"
14
14
  #include "fileops.h"
15
15
  #include "filebuf.h"
16
+ #include "netops.h"
16
17
  #include "refs.h"
17
18
  #include "repository.h"
18
19
 
@@ -36,6 +37,33 @@ int git_fetchhead_ref_cmp(const void *a, const void *b)
36
37
  return 0;
37
38
  }
38
39
 
40
+ static char *sanitized_remote_url(const char *remote_url)
41
+ {
42
+ gitno_connection_data url = {0};
43
+ char *sanitized = NULL;
44
+ int error;
45
+
46
+ if (gitno_connection_data_from_url(&url, remote_url, NULL) == 0) {
47
+ git_buf buf = GIT_BUF_INIT;
48
+
49
+ git__free(url.user);
50
+ git__free(url.pass);
51
+ url.user = url.pass = NULL;
52
+
53
+ if ((error = gitno_connection_data_fmt(&buf, &url)) < 0)
54
+ goto fallback;
55
+
56
+ sanitized = git_buf_detach(&buf);
57
+ }
58
+
59
+ fallback:
60
+ if (!sanitized)
61
+ sanitized = git__strdup(remote_url);
62
+
63
+ gitno_connection_data_free_ptrs(&url);
64
+ return sanitized;
65
+ }
66
+
39
67
  int git_fetchhead_ref_create(
40
68
  git_fetchhead_ref **out,
41
69
  git_oid *oid,
@@ -57,11 +85,15 @@ int git_fetchhead_ref_create(
57
85
  git_oid_cpy(&fetchhead_ref->oid, oid);
58
86
  fetchhead_ref->is_merge = is_merge;
59
87
 
60
- if (ref_name)
88
+ if (ref_name) {
61
89
  fetchhead_ref->ref_name = git__strdup(ref_name);
90
+ GIT_ERROR_CHECK_ALLOC(fetchhead_ref->ref_name);
91
+ }
62
92
 
63
- if (remote_url)
64
- fetchhead_ref->remote_url = git__strdup(remote_url);
93
+ if (remote_url) {
94
+ fetchhead_ref->remote_url = sanitized_remote_url(remote_url);
95
+ GIT_ERROR_CHECK_ALLOC(fetchhead_ref->remote_url);
96
+ }
65
97
 
66
98
  *out = fetchhead_ref;
67
99
 
@@ -44,18 +44,14 @@ static int verify_last_error(git_filebuf *file)
44
44
  static int lock_file(git_filebuf *file, int flags, mode_t mode)
45
45
  {
46
46
  if (git_path_exists(file->path_lock) == true) {
47
- if (flags & GIT_FILEBUF_FORCE)
48
- p_unlink(file->path_lock);
49
- else {
50
- git_error_clear(); /* actual OS error code just confuses */
51
- git_error_set(GIT_ERROR_OS,
52
- "failed to lock file '%s' for writing", file->path_lock);
53
- return GIT_ELOCKED;
54
- }
47
+ git_error_clear(); /* actual OS error code just confuses */
48
+ git_error_set(GIT_ERROR_OS,
49
+ "failed to lock file '%s' for writing", file->path_lock);
50
+ return GIT_ELOCKED;
55
51
  }
56
52
 
57
53
  /* create path to the file buffer is required */
58
- if (flags & GIT_FILEBUF_FORCE) {
54
+ if (flags & GIT_FILEBUF_CREATE_LEADING_DIRS) {
59
55
  /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */
60
56
  file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, mode);
61
57
  } else {
@@ -19,7 +19,7 @@
19
19
 
20
20
  #define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
21
21
  #define GIT_FILEBUF_APPEND (1 << 2)
22
- #define GIT_FILEBUF_FORCE (1 << 3)
22
+ #define GIT_FILEBUF_CREATE_LEADING_DIRS (1 << 3)
23
23
  #define GIT_FILEBUF_TEMPORARY (1 << 4)
24
24
  #define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5)
25
25
  #define GIT_FILEBUF_FSYNC (1 << 6)
@@ -476,6 +476,7 @@ int git_futils_mkdir(
476
476
  break;
477
477
  } else if (errno != ENOENT) {
478
478
  git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr);
479
+ error = -1;
479
480
  goto done;
480
481
  }
481
482
 
@@ -141,14 +141,21 @@ static void shutdown_common(void)
141
141
  */
142
142
  #if defined(GIT_THREADS) && defined(GIT_WIN32)
143
143
 
144
- static DWORD _tls_index;
144
+ static DWORD _fls_index;
145
145
  static volatile LONG _mutex = 0;
146
146
 
147
+ static void WINAPI fls_free(void *st)
148
+ {
149
+ git__global_state_cleanup(st);
150
+ git__free(st);
151
+ }
152
+
147
153
  static int synchronized_threads_init(void)
148
154
  {
149
155
  int error;
150
156
 
151
- _tls_index = TlsAlloc();
157
+ if ((_fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
158
+ return -1;
152
159
 
153
160
  git_threads_init();
154
161
 
@@ -190,9 +197,7 @@ int git_libgit2_shutdown(void)
190
197
  if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
191
198
  shutdown_common();
192
199
 
193
- git__free_tls_data();
194
-
195
- TlsFree(_tls_index);
200
+ FlsFree(_fls_index);
196
201
  git_mutex_free(&git__mwindow_mutex);
197
202
 
198
203
  #if defined(GIT_MSVC_CRTDBG)
@@ -213,7 +218,7 @@ git_global_st *git__global_state(void)
213
218
 
214
219
  assert(git_atomic_get(&git__n_inits) > 0);
215
220
 
216
- if ((ptr = TlsGetValue(_tls_index)) != NULL)
221
+ if ((ptr = FlsGetValue(_fls_index)) != NULL)
217
222
  return ptr;
218
223
 
219
224
  ptr = git__calloc(1, sizeof(git_global_st));
@@ -222,43 +227,10 @@ git_global_st *git__global_state(void)
222
227
 
223
228
  git_buf_init(&ptr->error_buf, 0);
224
229
 
225
- TlsSetValue(_tls_index, ptr);
230
+ FlsSetValue(_fls_index, ptr);
226
231
  return ptr;
227
232
  }
228
233
 
229
- /**
230
- * Free the TLS data associated with this thread.
231
- * This should only be used by the thread as it
232
- * is exiting.
233
- */
234
- void git__free_tls_data(void)
235
- {
236
- void *ptr = TlsGetValue(_tls_index);
237
- if (!ptr)
238
- return;
239
-
240
- git__global_state_cleanup(ptr);
241
- git__free(ptr);
242
- TlsSetValue(_tls_index, NULL);
243
- }
244
-
245
- BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
246
- {
247
- GIT_UNUSED(hInstDll);
248
- GIT_UNUSED(lpvReserved);
249
-
250
- /* This is how Windows lets us know our thread is being shut down */
251
- if (fdwReason == DLL_THREAD_DETACH) {
252
- git__free_tls_data();
253
- }
254
-
255
- /*
256
- * Windows pays attention to this during library loading. We don't do anything
257
- * so we trivially succeed.
258
- */
259
- return TRUE;
260
- }
261
-
262
234
  #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
263
235
 
264
236
  static pthread_key_t _tls_key;
@@ -35,8 +35,6 @@ typedef void (*git_global_shutdown_fn)(void);
35
35
 
36
36
  extern void git__on_shutdown(git_global_shutdown_fn callback);
37
37
 
38
- extern void git__free_tls_data(void);
39
-
40
38
  extern const char *git_libgit2__user_agent(void);
41
39
  extern const char *git_libgit2__ssl_ciphers(void);
42
40
 
@@ -453,7 +453,7 @@ static bool ignore_lookup_in_rules(
453
453
  int git_ignore__lookup(
454
454
  int *out, git_ignores *ignores, const char *pathname, git_dir_flag dir_flag)
455
455
  {
456
- unsigned int i;
456
+ size_t i;
457
457
  git_attr_file *file;
458
458
  git_attr_path path;
459
459
 
@@ -467,8 +467,11 @@ int git_ignore__lookup(
467
467
  if (ignore_lookup_in_rules(out, ignores->ign_internal, &path))
468
468
  goto cleanup;
469
469
 
470
- /* next process files in the path */
471
- git_vector_foreach(&ignores->ign_path, i, file) {
470
+ /* next process files in the path.
471
+ * this process has to process ignores in reverse order
472
+ * to ensure correct prioritization of rules
473
+ */
474
+ git_vector_rforeach(&ignores->ign_path, i, file) {
472
475
  if (ignore_lookup_in_rules(out, file, &path))
473
476
  goto cleanup;
474
477
  }
@@ -65,15 +65,25 @@ GIT_INLINE(int) git__is_int(long long p)
65
65
  # error compiler has add with overflow intrinsics but SIZE_MAX is unknown
66
66
  # endif
67
67
 
68
+ # define git__add_int_overflow(out, one, two) \
69
+ __builtin_sadd_overflow(one, two, out)
70
+ # define git__sub_int_overflow(out, one, two) \
71
+ __builtin_ssub_overflow(one, two, out)
72
+
68
73
  /* Use Microsoft's safe integer handling functions where available */
69
74
  #elif defined(_MSC_VER)
70
75
 
76
+ # define ENABLE_INTSAFE_SIGNED_FUNCTIONS
71
77
  # include <intsafe.h>
72
78
 
73
79
  # define git__add_sizet_overflow(out, one, two) \
74
80
  (SizeTAdd(one, two, out) != S_OK)
75
81
  # define git__multiply_sizet_overflow(out, one, two) \
76
82
  (SizeTMult(one, two, out) != S_OK)
83
+ #define git__add_int_overflow(out, one, two) \
84
+ (IntAdd(one, two, out) != S_OK)
85
+ #define git__sub_int_overflow(out, one, two) \
86
+ (IntSub(one, two, out) != S_OK)
77
87
 
78
88
  #else
79
89
 
@@ -101,6 +111,24 @@ GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t tw
101
111
  return false;
102
112
  }
103
113
 
114
+ GIT_INLINE(bool) git__add_int_overflow(int *out, int one, int two)
115
+ {
116
+ if ((two > 0 && one > (INT_MAX - two)) ||
117
+ (two < 0 && one < (INT_MIN - two)))
118
+ return true;
119
+ *out = one + two;
120
+ return false;
121
+ }
122
+
123
+ GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
124
+ {
125
+ if ((two > 0 && one < (INT_MIN + two)) ||
126
+ (two < 0 && one > (INT_MAX + two)))
127
+ return true;
128
+ *out = one - two;
129
+ return false;
130
+ }
131
+
104
132
  #endif
105
133
 
106
134
  #endif
@@ -543,8 +543,6 @@ static int tree_iterator_frame_init(
543
543
  new_frame = git_array_alloc(iter->frames);
544
544
  GIT_ERROR_CHECK_ALLOC(new_frame);
545
545
 
546
- memset(new_frame, 0, sizeof(tree_iterator_frame));
547
-
548
546
  if ((error = git_tree_dup(&dup, tree)) < 0)
549
547
  goto done;
550
548
 
@@ -552,19 +550,22 @@ static int tree_iterator_frame_init(
552
550
  new_frame->tree = dup;
553
551
 
554
552
  if (frame_entry &&
555
- (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
553
+ (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
556
554
  goto done;
557
555
 
558
556
  cmp = iterator__ignore_case(&iter->base) ?
559
557
  tree_iterator_entry_sort_icase : NULL;
560
558
 
561
- if ((error = git_vector_init(
562
- &new_frame->entries, dup->entries.size, cmp)) < 0)
559
+ if ((error = git_vector_init(&new_frame->entries,
560
+ dup->entries.size, cmp)) < 0)
563
561
  goto done;
564
562
 
565
563
  git_array_foreach(dup->entries, i, tree_entry) {
566
- new_entry = git_pool_malloc(&iter->entry_pool, 1);
567
- GIT_ERROR_CHECK_ALLOC(new_entry);
564
+ if ((new_entry = git_pool_malloc(&iter->entry_pool, 1)) == NULL) {
565
+ git_error_set_oom();
566
+ error = -1;
567
+ goto done;
568
+ }
568
569
 
569
570
  new_entry->tree_entry = tree_entry;
570
571
  new_entry->parent_path = new_frame->path.ptr;
@@ -2430,7 +2430,7 @@ static int write_merge_head(
2430
2430
  assert(repo && heads);
2431
2431
 
2432
2432
  if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 ||
2433
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
2433
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
2434
2434
  goto cleanup;
2435
2435
 
2436
2436
  for (i = 0; i < heads_len; i++) {
@@ -2458,7 +2458,7 @@ static int write_merge_mode(git_repository *repo)
2458
2458
  assert(repo);
2459
2459
 
2460
2460
  if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 ||
2461
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
2461
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
2462
2462
  goto cleanup;
2463
2463
 
2464
2464
  if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0)
@@ -2689,7 +2689,7 @@ static int write_merge_msg(
2689
2689
  entries[i].merge_head = heads[i];
2690
2690
 
2691
2691
  if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
2692
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
2692
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0 ||
2693
2693
  (error = git_filebuf_write(&file, "Merge ", 6)) < 0)
2694
2694
  goto cleanup;
2695
2695
 
@@ -206,6 +206,35 @@ cleanup:
206
206
  return error;
207
207
  }
208
208
 
209
+ int gitno_connection_data_fmt(git_buf *buf, gitno_connection_data *d)
210
+ {
211
+ if (d->host) {
212
+ git_buf_puts(buf, d->use_ssl ? prefix_https : prefix_http);
213
+
214
+ if (d->user) {
215
+ git_buf_puts(buf, d->user);
216
+
217
+ if (d->pass) {
218
+ git_buf_puts(buf, ":");
219
+ git_buf_puts(buf, d->pass);
220
+ }
221
+
222
+ git_buf_putc(buf, '@');
223
+ }
224
+
225
+ git_buf_puts(buf, d->host);
226
+
227
+ if (d->port && strcmp(d->port, gitno__default_port(d))) {
228
+ git_buf_putc(buf, ':');
229
+ git_buf_puts(buf, d->port);
230
+ }
231
+ }
232
+
233
+ git_buf_puts(buf, d->path ? d->path : "/");
234
+
235
+ return git_buf_oom(buf) ? -1 : 0;
236
+ }
237
+
209
238
  void gitno_connection_data_free_ptrs(gitno_connection_data *d)
210
239
  {
211
240
  git__free(d->host); d->host = NULL;
@@ -84,6 +84,9 @@ int gitno_connection_data_from_url(
84
84
  const char *url,
85
85
  const char *service_suffix);
86
86
 
87
+ /* Format a URL into a buffer */
88
+ int gitno_connection_data_fmt(git_buf *buf, gitno_connection_data *data);
89
+
87
90
  /* This frees all the pointers IN the struct, but not the struct itself. */
88
91
  void gitno_connection_data_free_ptrs(gitno_connection_data *data);
89
92
 
@@ -836,7 +836,7 @@ static int patch_generated_line_cb(
836
836
  {
837
837
  git_patch_generated *patch = payload;
838
838
  git_patch_hunk *hunk;
839
- git_diff_line *line;
839
+ git_diff_line *line;
840
840
 
841
841
  GIT_UNUSED(delta);
842
842
  GIT_UNUSED(hunk_);
@@ -58,31 +58,36 @@ static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx, size_t
58
58
  int error;
59
59
 
60
60
  if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0)
61
- goto done;
61
+ return error;
62
62
 
63
63
  git_parse_advance_chars(&ctx->parse_ctx, path_len);
64
64
 
65
65
  git_buf_rtrim(path);
66
66
 
67
- if (path->size > 0 && path->ptr[0] == '"')
68
- error = git_buf_unquote(path);
69
-
70
- if (error < 0)
71
- goto done;
67
+ if (path->size > 0 && path->ptr[0] == '"' &&
68
+ (error = git_buf_unquote(path)) < 0)
69
+ return error;
72
70
 
73
71
  git_path_squash_slashes(path);
74
72
 
75
- done:
76
- return error;
73
+ if (!path->size)
74
+ return git_parse_err("patch contains empty path at line %"PRIuZ,
75
+ ctx->parse_ctx.line_num);
76
+
77
+ return 0;
77
78
  }
78
79
 
79
80
  static int parse_header_path(char **out, git_patch_parse_ctx *ctx)
80
81
  {
81
82
  git_buf path = GIT_BUF_INIT;
82
- int error = parse_header_path_buf(&path, ctx, header_path_len(ctx));
83
+ int error;
83
84
 
85
+ if ((error = parse_header_path_buf(&path, ctx, header_path_len(ctx))) < 0)
86
+ goto out;
84
87
  *out = git_buf_detach(&path);
85
88
 
89
+ out:
90
+ git_buf_dispose(&path);
86
91
  return error;
87
92
  }
88
93
 
@@ -92,6 +97,12 @@ static int parse_header_git_oldpath(
92
97
  git_buf old_path = GIT_BUF_INIT;
93
98
  int error;
94
99
 
100
+ if (patch->old_path) {
101
+ error = git_parse_err("patch contains duplicate old path at line %"PRIuZ,
102
+ ctx->parse_ctx.line_num);
103
+ goto out;
104
+ }
105
+
95
106
  if ((error = parse_header_path_buf(&old_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
96
107
  goto out;
97
108
 
@@ -108,9 +119,14 @@ static int parse_header_git_newpath(
108
119
  git_buf new_path = GIT_BUF_INIT;
109
120
  int error;
110
121
 
111
- if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
122
+ if (patch->new_path) {
123
+ error = git_parse_err("patch contains duplicate new path at line %"PRIuZ,
124
+ ctx->parse_ctx.line_num);
112
125
  goto out;
126
+ }
113
127
 
128
+ if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
129
+ goto out;
114
130
  patch->new_path = git_buf_detach(&new_path);
115
131
 
116
132
  out:
@@ -377,6 +393,7 @@ static const parse_header_transition transitions[] = {
377
393
  { "index " , STATE_DIFF, STATE_INDEX, parse_header_git_index },
378
394
  { "index " , STATE_END, STATE_INDEX, parse_header_git_index },
379
395
 
396
+ { "--- " , STATE_DIFF, STATE_PATH, parse_header_git_oldpath },
380
397
  { "--- " , STATE_INDEX, STATE_PATH, parse_header_git_oldpath },
381
398
  { "+++ " , STATE_PATH, STATE_END, parse_header_git_newpath },
382
399
  { "GIT binary patch" , STATE_INDEX, STATE_END, NULL },
@@ -394,6 +411,7 @@ static const parse_header_transition transitions[] = {
394
411
  /* Next patch */
395
412
  { "diff --git " , STATE_END, 0, NULL },
396
413
  { "@@ -" , STATE_END, 0, NULL },
414
+ { "-- " , STATE_INDEX, 0, NULL },
397
415
  { "-- " , STATE_END, 0, NULL },
398
416
  };
399
417
 
@@ -524,6 +542,14 @@ fail:
524
542
  return -1;
525
543
  }
526
544
 
545
+ static int eof_for_origin(int origin) {
546
+ if (origin == GIT_DIFF_LINE_ADDITION)
547
+ return GIT_DIFF_LINE_ADD_EOFNL;
548
+ if (origin == GIT_DIFF_LINE_DELETION)
549
+ return GIT_DIFF_LINE_DEL_EOFNL;
550
+ return GIT_DIFF_LINE_CONTEXT_EOFNL;
551
+ }
552
+
527
553
  static int parse_hunk_body(
528
554
  git_patch_parsed *patch,
529
555
  git_patch_hunk *hunk,
@@ -534,6 +560,7 @@ static int parse_hunk_body(
534
560
 
535
561
  int oldlines = hunk->hunk.old_lines;
536
562
  int newlines = hunk->hunk.new_lines;
563
+ int last_origin = 0;
537
564
 
538
565
  for (;
539
566
  ctx->parse_ctx.remain_len > 1 &&
@@ -541,11 +568,17 @@ static int parse_hunk_body(
541
568
  !git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -");
542
569
  git_parse_advance_line(&ctx->parse_ctx)) {
543
570
 
571
+ int old_lineno, new_lineno, origin, prefix = 1;
544
572
  char c;
545
- int origin;
546
- int prefix = 1;
547
- int old_lineno = hunk->hunk.old_start + (hunk->hunk.old_lines - oldlines);
548
- int new_lineno = hunk->hunk.new_start + (hunk->hunk.new_lines - newlines);
573
+
574
+ if (git__add_int_overflow(&old_lineno, hunk->hunk.old_start, hunk->hunk.old_lines) ||
575
+ git__sub_int_overflow(&old_lineno, old_lineno, oldlines) ||
576
+ git__add_int_overflow(&new_lineno, hunk->hunk.new_start, hunk->hunk.new_lines) ||
577
+ git__sub_int_overflow(&new_lineno, new_lineno, newlines)) {
578
+ error = git_parse_err("unrepresentable line count at line %"PRIuZ,
579
+ ctx->parse_ctx.line_num);
580
+ goto done;
581
+ }
549
582
 
550
583
  if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') {
551
584
  error = git_parse_err("invalid patch instruction at line %"PRIuZ,
@@ -578,6 +611,21 @@ static int parse_hunk_body(
578
611
  old_lineno = -1;
579
612
  break;
580
613
 
614
+ case '\\':
615
+ /*
616
+ * If there are no oldlines left, then this is probably
617
+ * the "" marker. Do not
618
+ * verify its format, as it may be localized.
619
+ */
620
+ if (!oldlines) {
621
+ prefix = 0;
622
+ origin = eof_for_origin(last_origin);
623
+ old_lineno = -1;
624
+ new_lineno = -1;
625
+ break;
626
+ }
627
+ /* fall through */
628
+
581
629
  default:
582
630
  error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
583
631
  goto done;
@@ -588,8 +636,9 @@ static int parse_hunk_body(
588
636
 
589
637
  memset(line, 0x0, sizeof(git_diff_line));
590
638
 
591
- line->content = ctx->parse_ctx.line + prefix;
592
639
  line->content_len = ctx->parse_ctx.line_len - prefix;
640
+ line->content = git__strndup(ctx->parse_ctx.line + prefix, line->content_len);
641
+ GIT_ERROR_CHECK_ALLOC(line->content);
593
642
  line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
594
643
  line->origin = origin;
595
644
  line->num_lines = 1;
@@ -597,6 +646,8 @@ static int parse_hunk_body(
597
646
  line->new_lineno = new_lineno;
598
647
 
599
648
  hunk->line_count++;
649
+
650
+ last_origin = origin;
600
651
  }
601
652
 
602
653
  if (oldlines || newlines) {
@@ -606,7 +657,8 @@ static int parse_hunk_body(
606
657
  goto done;
607
658
  }
608
659
 
609
- /* Handle "". Only expect the leading
660
+ /*
661
+ * Handle "". Only expect the leading
610
662
  * backslash, though, because the rest of the string could be
611
663
  * localized. Because `diff` optimizes for the case where you
612
664
  * want to apply the patch by hand.
@@ -617,11 +669,25 @@ static int parse_hunk_body(
617
669
  line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1);
618
670
 
619
671
  if (line->content_len < 1) {
620
- error = git_parse_err("cannot trim trailing newline of empty line");
672
+ error = git_parse_err("last line has no trailing newline");
621
673
  goto done;
622
674
  }
623
675
 
624
- line->content_len--;
676
+ line = git_array_alloc(patch->base.lines);
677
+ GIT_ERROR_CHECK_ALLOC(line);
678
+
679
+ memset(line, 0x0, sizeof(git_diff_line));
680
+
681
+ line->content_len = ctx->parse_ctx.line_len;
682
+ line->content = git__strndup(ctx->parse_ctx.line, line->content_len);
683
+ GIT_ERROR_CHECK_ALLOC(line->content);
684
+ line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
685
+ line->origin = eof_for_origin(last_origin);
686
+ line->num_lines = 1;
687
+ line->old_lineno = -1;
688
+ line->new_lineno = -1;
689
+
690
+ hunk->line_count++;
625
691
 
626
692
  git_parse_advance_line(&ctx->parse_ctx);
627
693
  }
@@ -730,7 +796,7 @@ static int parse_patch_binary_side(
730
796
 
731
797
  encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5;
732
798
 
733
- if (encoded_len > ctx->parse_ctx.line_len - 1) {
799
+ if (!encoded_len || !ctx->parse_ctx.line_len || encoded_len > ctx->parse_ctx.line_len - 1) {
734
800
  error = git_parse_err("truncated binary data at line %"PRIuZ, ctx->parse_ctx.line_num);
735
801
  goto done;
736
802
  }
@@ -800,12 +866,18 @@ static int parse_patch_binary_nodata(
800
866
  git_patch_parsed *patch,
801
867
  git_patch_parse_ctx *ctx)
802
868
  {
869
+ const char *old = patch->old_path ? patch->old_path : patch->header_old_path;
870
+ const char *new = patch->new_path ? patch->new_path : patch->header_new_path;
871
+
872
+ if (!old || !new)
873
+ return git_parse_err("corrupt binary data without paths at line %"PRIuZ, ctx->parse_ctx.line_num);
874
+
803
875
  if (git_parse_advance_expected_str(&ctx->parse_ctx, "Binary files ") < 0 ||
804
- git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_old_path) < 0 ||
805
- git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 ||
806
- git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_new_path) < 0 ||
807
- git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 ||
808
- git_parse_advance_nl(&ctx->parse_ctx) < 0)
876
+ git_parse_advance_expected_str(&ctx->parse_ctx, old) < 0 ||
877
+ git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 ||
878
+ git_parse_advance_expected_str(&ctx->parse_ctx, new) < 0 ||
879
+ git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 ||
880
+ git_parse_advance_nl(&ctx->parse_ctx) < 0)
809
881
  return git_parse_err("corrupt git binary header at line %"PRIuZ, ctx->parse_ctx.line_num);
810
882
 
811
883
  patch->base.binary.contains_data = 0;
@@ -1038,6 +1110,8 @@ int git_patch_parsed_from_diff(git_patch **out, git_diff *d, size_t idx)
1038
1110
  static void patch_parsed__free(git_patch *p)
1039
1111
  {
1040
1112
  git_patch_parsed *patch = (git_patch_parsed *)p;
1113
+ git_diff_line *line;
1114
+ size_t i;
1041
1115
 
1042
1116
  if (!patch)
1043
1117
  return;
@@ -1047,6 +1121,8 @@ static void patch_parsed__free(git_patch *p)
1047
1121
  git__free((char *)patch->base.binary.old_file.data);
1048
1122
  git__free((char *)patch->base.binary.new_file.data);
1049
1123
  git_array_clear(patch->base.hunks);
1124
+ git_array_foreach(patch->base.lines, i, line)
1125
+ git__free((char *) line->content);
1050
1126
  git_array_clear(patch->base.lines);
1051
1127
  git__free(patch->base.delta);
1052
1128