diff --git a/editors/patch.c b/editors/patch.c
index e0fb58f87..7b391603d 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -44,23 +44,23 @@ static unsigned copy_lines(FILE *src_stream, FILE *dest_stream, unsigned lines_c
* returns malloc'ed filename
* NB: frees 1st argument!
*/
-static char *extract_filename_and_free_line(char *line, int patch_level)
+static char *extract_filename(char *line, int patch_level, const char *pat)
{
- char *temp, *filename_start_ptr = line + 4;
+ char *temp = NULL, *filename_start_ptr = line + 4;
- /* Terminate string at end of source filename */
- temp = strchrnul(filename_start_ptr, '\t');
- *temp = '\0';
+ if (strncmp(line, pat, 4) == 0) {
+ /* Terminate string at end of source filename */
+ line[strcspn(line,"\t\n\r")] = '\0';
- /* Skip over (patch_level) number of leading directories */
- while (patch_level--) {
- temp = strchr(filename_start_ptr, '/');
- if (!temp)
- break;
- filename_start_ptr = temp + 1;
+ /* Skip over (patch_level) number of leading directories */
+ while (patch_level--) {
+ temp = strchr(filename_start_ptr, '/');
+ if (!temp)
+ break;
+ filename_start_ptr = temp + 1;
+ }
+ temp = xstrdup(filename_start_ptr);
}
-
- temp = xstrdup(filename_start_ptr);
free(line);
return temp;
}
@@ -100,30 +100,26 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
/* Skip everything upto the "---" marker
* No need to parse the lines "Only in
", and "diff "
*/
- while (strncmp(patch_line, "--- ", 4) != 0) {
- free(patch_line);
+ do {
+ /* Extract the filename used before the patch was generated */
+ original_filename = extract_filename(patch_line, patch_level, "--- ");
patch_line = xmalloc_getline(patch_file);
- if (!patch_line)
- bb_error_msg_and_die("invalid patch");
+ if (!patch_line) goto quit;
+ } while (!original_filename);
+
+ new_filename = extract_filename(patch_line, patch_level, "+++ ");
+ if (!new_filename) {
+ bb_error_msg_and_die("invalid patch");
}
- /* Extract the filename used before the patch was generated */
- original_filename = extract_filename_and_free_line(patch_line, patch_level);
-
- patch_line = xmalloc_getline(patch_file);
- if (!patch_line || strncmp(patch_line, "+++ ", 4) != 0)
- bb_error_msg_and_die("invalid patch");
- new_filename = extract_filename_and_free_line(patch_line, patch_level);
-
- /* Get access rights from the file to be patched, -1 file does not exist */
+ /* Get access rights from the file to be patched */
if (stat(new_filename, &saved_stat) != 0) {
- char *line_ptr;
- /* Create leading directories */
- line_ptr = strrchr(new_filename, '/');
- if (line_ptr) {
- *line_ptr = '\0';
+ char *slash = strrchr(new_filename, '/');
+ if (slash) {
+ /* Create leading directories */
+ *slash = '\0';
bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
- *line_ptr = '/';
+ *slash = '/';
}
backup_filename = NULL;
saved_stat.st_mode = 0644;
@@ -134,10 +130,16 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
dst_stream = xfopen(new_filename, "w");
fchmod(fileno(dst_stream), saved_stat.st_mode);
src_stream = NULL;
-
- if (backup_filename && !stat(original_filename, &saved_stat)) {
- src_stream = xfopen((strcmp(original_filename, new_filename)) ?
- original_filename : backup_filename, "r");
+ if (backup_filename && stat(original_filename, &saved_stat) == 0) {
+ // strcmp() is never 0! Otherwise:
+ // original_filename == new_filename,
+ // stat(original_filename) == stat(new_filename),
+ // stat(new_filename) == 0,
+ // but we renamed new_filename if it existed!
+ // stat() must fail!
+ //src_stream = xfopen((strcmp(original_filename, new_filename)) ?
+ // original_filename : backup_filename, "r");
+ src_stream = xfopen(original_filename, "r");
}
printf("patching file %s\n", new_filename);
@@ -147,16 +149,12 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
while (patch_line) {
unsigned count;
unsigned src_beg_line;
- unsigned unused;
- unsigned hunk_offset_start = 0;
- smallint hunk_error = 0;
+ unsigned hunk_offset_start;
+ unsigned src_last_line = 1;
- /* This bit should be improved */
- if ((sscanf(patch_line, "@@ -%d,%d +%d,%d @@", &src_beg_line, &unused, &dest_beg_line, &unused) != 4)
- && (sscanf(patch_line, "@@ -%d,%d +%d @@", &src_beg_line, &unused, &dest_beg_line) != 3)
- && (sscanf(patch_line, "@@ -%d +%d,%d @@", &src_beg_line, &dest_beg_line, &unused) != 3)
- ) {
- /* No more hunks for this file */
+ if ((sscanf(patch_line, "@@ -%d,%d +%d", &src_beg_line, &src_last_line, &dest_beg_line) != 3)
+ && (sscanf(patch_line, "@@ -%d +%d", &src_beg_line, &dest_beg_line) != 2)
+ ) { /* No more hunks for this file */
break;
}
hunk_count++;
@@ -172,14 +170,22 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
dest_cur_line += count;
copy_trailing_lines_flag = 1;
}
- hunk_offset_start = src_cur_line;
+ src_last_line += hunk_offset_start = src_cur_line;
while (1) {
free(patch_line);
patch_line = xmalloc_fgets(patch_file);
- if (patch_line == NULL) break;
- if ((*patch_line == '-') || (*patch_line == ' ')) {
+ if (patch_line == NULL)
+ break; /* EOF */
+ if ((*patch_line != '-') && (*patch_line != '+')
+ && (*patch_line != ' ')
+ ) {
+ break; /* End of hunk */
+ }
+ if (*patch_line != '+') { /* '-', ' ' or '\n' */
char *src_line = NULL;
+ if (src_cur_line == src_last_line)
+ break;
if (src_stream) {
src_line = xmalloc_fgets(src_stream);
if (src_line) {
@@ -188,26 +194,19 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
free(src_line);
if (diff) src_line = NULL;
}
- if (!src_line) {
- bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start);
- hunk_error = 1;
- break;
- }
}
- if (*patch_line == ' ') {
- fputs(patch_line + 1, dst_stream);
- dest_cur_line++;
+ if (!src_line) {
+ bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
+ bad_hunk_count++;
+ break;
+ }
+ if (*patch_line == '-') {
+ continue;
}
- } else if (*patch_line == '+') {
- fputs(patch_line + 1, dst_stream);
- dest_cur_line++;
- } else {
- break;
}
+ fputs(patch_line + 1, dst_stream);
+ dest_cur_line++;
} /* end of while loop handling one hunk */
- if (hunk_error) {
- bad_hunk_count++;
- }
} /* end of while loop handling one file */
/* Cleanup last patched file */
@@ -217,9 +216,7 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
if (src_stream) {
fclose(src_stream);
}
- if (dst_stream) {
- fclose(dst_stream);
- }
+ fclose(dst_stream);
if (bad_hunk_count) {
ret = 1;
bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count);
@@ -232,11 +229,12 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
if ((dest_cur_line == 0) || (dest_beg_line == 0)) {
/* The new patched file is empty, remove it */
xunlink(new_filename);
- if (strcmp(new_filename, original_filename) != 0)
- xunlink(original_filename);
+ /* original_filename and new_filename may be the same file */
+ unlink(original_filename);
}
}
} /* end of "while there are patch lines" */
+quit:
/* 0 = SUCCESS
* 1 = Some hunks failed