21
21
static int merge_patch = 1 ;
22
22
static const char apply_usage [] = "git-apply <patch>" ;
23
23
24
+ static int linenr = 1 ;
25
+
24
26
#define CHUNKSIZE (8192)
25
27
26
28
static void * read_patch_file (int fd , unsigned long * sizep )
@@ -77,7 +79,7 @@ static int parse_git_header(char *line, unsigned int size)
77
79
{
78
80
unsigned long offset , len ;
79
81
80
- for (offset = 0 ; size > 0 ; offset += len , size -= len , line += len ) {
82
+ for (offset = 0 ; size > 0 ; offset += len , size -= len , line += len , linenr ++ ) {
81
83
len = linelen (line , size );
82
84
if (!len )
83
85
break ;
@@ -104,11 +106,60 @@ static int parse_git_header(char *line, unsigned int size)
104
106
return offset ? :-1 ;
105
107
}
106
108
109
+ static int parse_num (const char * line , int len , int offset , const char * expect , unsigned long * p )
110
+ {
111
+ char * ptr ;
112
+ int digits , ex ;
113
+
114
+ if (offset < 0 || offset >= len )
115
+ return -1 ;
116
+ line += offset ;
117
+ len -= offset ;
118
+
119
+ if (!isdigit (* line ))
120
+ return -1 ;
121
+ * p = strtoul (line , & ptr , 10 );
122
+
123
+ digits = ptr - line ;
124
+
125
+ offset += digits ;
126
+ line += digits ;
127
+ len -= digits ;
128
+
129
+ ex = strlen (expect );
130
+ if (ex > len )
131
+ return -1 ;
132
+ if (memcmp (line , expect , ex ))
133
+ return -1 ;
134
+
135
+ return offset + ex ;
136
+ }
137
+
138
+ /*
139
+ * Parse a unified diff fragment header of the
140
+ * form "@@ -a,b +c,d @@"
141
+ */
142
+ static int parse_fragment_header (char * line , int len , unsigned long * pos )
143
+ {
144
+ int offset ;
145
+
146
+ if (!len || line [len - 1 ] != '\n' )
147
+ return -1 ;
148
+
149
+ /* Figure out the number of lines in a fragment */
150
+ offset = parse_num (line , len , 4 , "," , pos );
151
+ offset = parse_num (line , len , offset , " +" , pos + 1 );
152
+ offset = parse_num (line , len , offset , "," , pos + 2 );
153
+ offset = parse_num (line , len , offset , " @@" , pos + 3 );
154
+
155
+ return offset ;
156
+ }
157
+
107
158
static int find_header (char * line , unsigned long size , int * hdrsize )
108
159
{
109
160
unsigned long offset , len ;
110
161
111
- for (offset = 0 ; size > 0 ; offset += len , size -= len , line += len ) {
162
+ for (offset = 0 ; size > 0 ; offset += len , size -= len , line += len , linenr ++ ) {
112
163
unsigned long nextlen ;
113
164
114
165
len = linelen (line , size );
@@ -118,6 +169,19 @@ static int find_header(char *line, unsigned long size, int *hdrsize)
118
169
/* Testing this early allows us to take a few shortcuts.. */
119
170
if (len < 6 )
120
171
continue ;
172
+
173
+ /*
174
+ * Make sure we don't find any unconnected patch fragmants.
175
+ * That's a sign that we didn't find a header, and that a
176
+ * patch has become corrupted/broken up.
177
+ */
178
+ if (!memcmp ("@@ -" , line , 4 )) {
179
+ unsigned long pos [4 ];
180
+ if (parse_fragment_header (line , len , pos ) < 0 )
181
+ continue ;
182
+ error ("patch fragment without header at line %d: %.*s" , linenr , len - 1 , line );
183
+ }
184
+
121
185
if (size < len + 6 )
122
186
break ;
123
187
@@ -149,40 +213,12 @@ static int find_header(char *line, unsigned long size, int *hdrsize)
149
213
150
214
/* Ok, we'll consider it a patch */
151
215
* hdrsize = len + nextlen ;
216
+ linenr += 2 ;
152
217
return offset ;
153
218
}
154
219
return -1 ;
155
220
}
156
221
157
- static int parse_num (const char * line , int len , int offset , const char * expect , unsigned long * p )
158
- {
159
- char * ptr ;
160
- int digits , ex ;
161
-
162
- if (offset < 0 || offset >= len )
163
- return -1 ;
164
- line += offset ;
165
- len -= offset ;
166
-
167
- if (!isdigit (* line ))
168
- return -1 ;
169
- * p = strtoul (line , & ptr , 10 );
170
-
171
- digits = ptr - line ;
172
-
173
- offset += digits ;
174
- line += digits ;
175
- len -= digits ;
176
-
177
- ex = strlen (expect );
178
- if (ex > len )
179
- return -1 ;
180
- if (memcmp (line , expect , ex ))
181
- return -1 ;
182
-
183
- return offset + ex ;
184
- }
185
-
186
222
/*
187
223
* Parse a unified diff. Note that this really needs
188
224
* to parse each fragment separately, since the only
@@ -193,23 +229,19 @@ static int parse_num(const char *line, int len, int offset, const char *expect,
193
229
static int apply_fragment (char * line , unsigned long size )
194
230
{
195
231
int len = linelen (line , size ), offset ;
196
- unsigned long oldpos , oldlines , newpos , newlines ;
232
+ unsigned long pos [ 4 ] , oldlines , newlines ;
197
233
198
- if (!len || line [len - 1 ] != '\n' )
199
- return -1 ;
200
-
201
- /* Figure out the number of lines in a fragment */
202
- offset = parse_num (line , len , 4 , "," , & oldpos );
203
- offset = parse_num (line , len , offset , " +" , & oldlines );
204
- offset = parse_num (line , len , offset , "," , & newpos );
205
- offset = parse_num (line , len , offset , " @@" , & newlines );
234
+ offset = parse_fragment_header (line , len , pos );
206
235
if (offset < 0 )
207
236
return -1 ;
237
+ oldlines = pos [1 ];
238
+ newlines = pos [3 ];
208
239
209
240
/* Parse the thing.. */
210
241
line += len ;
211
242
size -= len ;
212
- for (offset = len ; size > 0 ; offset += len , size -= len , line += len ) {
243
+ linenr ++ ;
244
+ for (offset = len ; size > 0 ; offset += len , size -= len , line += len , linenr ++ ) {
213
245
if (!oldlines && !newlines )
214
246
break ;
215
247
len = linelen (line , size );
@@ -240,7 +272,7 @@ static int apply_single_patch(char *line, unsigned long size)
240
272
while (size > 4 && !memcmp (line , "@@ -" , 4 )) {
241
273
int len = apply_fragment (line , size );
242
274
if (len <= 0 )
243
- die ("corrupt patch" );
275
+ die ("corrupt patch at line %d" , linenr );
244
276
245
277
printf ("applying fragment:\n%.*s\n\n" , len , line );
246
278
0 commit comments