rugged 0.28.4.1 → 0.28.5

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