Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/editors/patch.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/editors/patch.c
r1765 r2725 1 /* vi: set sw=4 ts=4: */ 2 /* 3 * busybox patch applet to handle the unified diff format. 4 * Copyright (C) 2003 Glenn McGrath <bug1@iinet.net.au> 1 /* vi: set sw=4 ts=4: 5 2 * 6 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 3 * Apply a "universal" diff. 4 * Adapted from toybox's patch implementation. 7 5 * 8 * This applet is written to work with patches generated by GNU diff, 9 * where there is equivalent functionality busybox patch shall behave 10 * as per GNU patch. 6 * Copyright 2007 Rob Landley <rob@landley.net> 11 7 * 12 * There is a SUSv3 specification for patch, however it looks to be 13 * incomplete, it doesnt even mention unified diff format. 14 * http://www.opengroup.org/onlinepubs/007904975/utilities/patch.html 8 * see http://www.opengroup.org/onlinepubs/009695399/utilities/patch.html 9 * (But only does -u, because who still cares about "ed"?) 15 10 * 16 * Issues 17 * - Non-interactive 18 * - Patches must apply cleanly or patch (not just one hunk) will fail. 19 * - Reject file isnt saved 11 * TODO: 12 * -b backup 13 * -l treat all whitespace as a single space 14 * -d chdir first 15 * -D define wrap #ifdef and #ifndef around changes 16 * -o outfile output here instead of in place 17 * -r rejectfile write rejected hunks to this file 18 * 19 * -f force (no questions asked) 20 * -F fuzz (number, default 2) 21 * [file] which file to patch 20 22 */ 21 23 22 #include <getopt.h> 24 //applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 25 26 //kbuild:lib-$(CONFIG_PATCH) += patch.o 27 28 //config:config PATCH 29 //config: bool "patch" 30 //config: default y 31 //config: help 32 //config: Apply a unified diff formatted patch. 33 34 //usage:#define patch_trivial_usage 35 //usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" 36 //usage:#define patch_full_usage "\n\n" 37 //usage: IF_LONG_OPTS( 38 //usage: " -p,--strip N Strip N leading components from file names" 39 //usage: "\n -i,--input DIFF Read DIFF instead of stdin" 40 //usage: "\n -R,--reverse Reverse patch" 41 //usage: "\n -N,--forward Ignore already applied patches" 42 //usage: "\n --dry-run Don't actually change files" 43 //usage: "\n -E,--remove-empty-files Remove output files if they become empty" 44 //usage: ) 45 //usage: IF_NOT_LONG_OPTS( 46 //usage: " -p N Strip N leading components from file names" 47 //usage: "\n -i DIFF Read DIFF instead of stdin" 48 //usage: "\n -R Reverse patch" 49 //usage: "\n -N Ignore already applied patches" 50 //usage: "\n -E Remove output files if they become empty" 51 //usage: ) 52 //usage: 53 //usage:#define patch_example_usage 54 //usage: "$ patch -p1 < example.diff\n" 55 //usage: "$ patch -p0 -i example.diff" 23 56 24 57 #include "libbb.h" 25 58 26 static unsigned int copy_lines(FILE *src_stream, FILE *dest_stream, const unsigned int lines_count) 27 { 28 unsigned int i = 0; 29 30 while (src_stream && (i < lines_count)) { 31 char *line; 32 line = xmalloc_fgets(src_stream); 33 if (line == NULL) { 34 break; 35 } 36 if (fputs(line, dest_stream) == EOF) { 37 bb_perror_msg_and_die("error writing to new file"); 38 } 39 free(line); 40 41 i++; 42 } 43 return i; 44 } 45 46 /* If patch_level is -1 it will remove all directory names 47 * char *line must be greater than 4 chars 48 * returns NULL if the file doesnt exist or error 49 * returns malloc'ed filename 50 */ 51 52 static char *extract_filename(char *line, int patch_level) 53 { 54 char *temp, *filename_start_ptr = line + 4; 55 int i; 56 57 /* Terminate string at end of source filename */ 58 temp = strchrnul(filename_start_ptr, '\t'); 59 *temp = '\0'; 60 61 /* Skip over (patch_level) number of leading directories */ 62 if (patch_level == -1) 63 patch_level = INT_MAX; 64 for (i = 0; i < patch_level; i++) { 65 temp = strchr(filename_start_ptr, '/'); 66 if (!temp) 67 break; 68 filename_start_ptr = temp + 1; 69 } 70 71 return xstrdup(filename_start_ptr); 72 } 73 74 static int file_doesnt_exist(const char *filename) 75 { 76 struct stat statbuf; 77 return stat(filename, &statbuf); 78 } 79 80 int patch_main(int argc, char **argv); 81 int patch_main(int argc, char **argv) 82 { 83 int patch_level = -1; 84 char *patch_line; 85 int ret; 86 FILE *patch_file = NULL; 87 88 { 89 char *p, *i; 90 ret = getopt32(argv, "p:i:", &p, &i); 91 if (ret & 1) 92 patch_level = xatol_range(p, -1, USHRT_MAX); 93 if (ret & 2) { 94 patch_file = xfopen(i, "r"); 95 } else { 96 patch_file = stdin; 97 } 98 ret = 0; 99 } 100 101 patch_line = xmalloc_getline(patch_file); 102 while (patch_line) { 103 FILE *src_stream; 104 FILE *dst_stream; 105 char *original_filename; 106 char *new_filename; 107 char *backup_filename; 108 unsigned int src_cur_line = 1; 109 unsigned int dest_cur_line = 0; 110 unsigned int dest_beg_line; 111 unsigned int bad_hunk_count = 0; 112 unsigned int hunk_count = 0; 113 char copy_trailing_lines_flag = 0; 114 115 /* Skip everything upto the "---" marker 116 * No need to parse the lines "Only in <dir>", and "diff <args>" 117 */ 118 while (patch_line && strncmp(patch_line, "--- ", 4) != 0) { 119 free(patch_line); 120 patch_line = xmalloc_getline(patch_file); 121 } 122 /* FIXME: patch_line NULL check?? */ 123 124 /* Extract the filename used before the patch was generated */ 125 original_filename = extract_filename(patch_line, patch_level); 126 free(patch_line); 127 128 patch_line = xmalloc_getline(patch_file); 129 /* FIXME: NULL check?? */ 130 if (strncmp(patch_line, "+++ ", 4) != 0) { 131 ret = 2; 132 bb_error_msg("invalid patch"); 133 continue; 134 } 135 new_filename = extract_filename(patch_line, patch_level); 136 free(patch_line); 137 138 if (file_doesnt_exist(new_filename)) { 139 char *line_ptr; 140 /* Create leading directories */ 141 line_ptr = strrchr(new_filename, '/'); 142 if (line_ptr) { 143 *line_ptr = '\0'; 144 bb_make_directory(new_filename, -1, FILEUTILS_RECUR); 145 *line_ptr = '/'; 59 60 // libbb candidate? 61 62 struct double_list { 63 struct double_list *next; 64 struct double_list *prev; 65 char *data; 66 }; 67 68 // Free all the elements of a linked list 69 // Call freeit() on each element before freeing it. 70 static 71 void dlist_free(struct double_list *list, void (*freeit)(void *data)) 72 { 73 while (list) { 74 void *pop = list; 75 list = list->next; 76 freeit(pop); 77 // Bail out also if list is circular. 78 if (list == pop) break; 79 } 80 } 81 82 // Add an entry before "list" element in (circular) doubly linked list 83 static 84 struct double_list *dlist_add(struct double_list **list, char *data) 85 { 86 struct double_list *llist; 87 struct double_list *line = xmalloc(sizeof(*line)); 88 89 line->data = data; 90 llist = *list; 91 if (llist) { 92 struct double_list *p; 93 line->next = llist; 94 p = line->prev = llist->prev; 95 // (list is circular, we assume p is never NULL) 96 p->next = line; 97 llist->prev = line; 98 } else 99 *list = line->next = line->prev = line; 100 101 return line; 102 } 103 104 105 struct globals { 106 char *infile; 107 long prefix; 108 109 struct double_list *current_hunk; 110 111 long oldline, oldlen, newline, newlen; 112 long linenum; 113 int context, state, hunknum; 114 int filein, fileout; 115 char *tempname; 116 117 int exitval; 118 }; 119 #define TT (*ptr_to_globals) 120 #define INIT_TT() do { \ 121 SET_PTR_TO_GLOBALS(xzalloc(sizeof(TT))); \ 122 } while (0) 123 124 125 #define FLAG_STR "Rup:i:NEx" 126 /* FLAG_REVERSE must be == 1! Code uses this fact. */ 127 #define FLAG_REVERSE (1 << 0) 128 #define FLAG_u (1 << 1) 129 #define FLAG_PATHLEN (1 << 2) 130 #define FLAG_INPUT (1 << 3) 131 #define FLAG_IGNORE (1 << 4) 132 #define FLAG_RMEMPTY (1 << 5) 133 //non-standard: 134 #define FLAG_DEBUG (1 << 6) 135 136 // Dispose of a line of input, either by writing it out or discarding it. 137 138 // state < 2: just free 139 // state = 2: write whole line to stderr 140 // state = 3: write whole line to fileout 141 // state > 3: write line+1 to fileout when *line != state 142 143 #define PATCH_DEBUG (option_mask32 & FLAG_DEBUG) 144 145 static void do_line(void *data) 146 { 147 struct double_list *dlist = data; 148 149 if (TT.state>1 && *dlist->data != TT.state) 150 fdprintf(TT.state == 2 ? 2 : TT.fileout, 151 "%s\n", dlist->data+(TT.state>3 ? 1 : 0)); 152 153 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); 154 155 free(dlist->data); 156 free(dlist); 157 } 158 159 static void finish_oldfile(void) 160 { 161 if (TT.tempname) { 162 // Copy the rest of the data and replace the original with the copy. 163 char *temp; 164 165 if (TT.filein != -1) { 166 bb_copyfd_eof(TT.filein, TT.fileout); 167 xclose(TT.filein); 168 } 169 xclose(TT.fileout); 170 171 temp = xstrdup(TT.tempname); 172 temp[strlen(temp) - 6] = '\0'; 173 rename(TT.tempname, temp); 174 free(temp); 175 176 free(TT.tempname); 177 TT.tempname = NULL; 178 } 179 TT.fileout = TT.filein = -1; 180 } 181 182 static void fail_hunk(void) 183 { 184 if (!TT.current_hunk) return; 185 186 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); 187 TT.exitval = 1; 188 189 // If we got to this point, we've seeked to the end. Discard changes to 190 // this file and advance to next file. 191 192 TT.state = 2; 193 TT.current_hunk->prev->next = NULL; 194 dlist_free(TT.current_hunk, do_line); 195 TT.current_hunk = NULL; 196 197 // Abort the copy and delete the temporary file. 198 close(TT.filein); 199 close(TT.fileout); 200 unlink(TT.tempname); 201 free(TT.tempname); 202 TT.tempname = NULL; 203 204 TT.state = 0; 205 } 206 207 // Given a hunk of a unified diff, make the appropriate change to the file. 208 // This does not use the location information, but instead treats a hunk 209 // as a sort of regex. Copies data from input to output until it finds 210 // the change to be made, then outputs the changed data and returns. 211 // (Finding EOF first is an error.) This is a single pass operation, so 212 // multiple hunks must occur in order in the file. 213 214 static int apply_one_hunk(void) 215 { 216 struct double_list *plist, *buf = NULL, *check; 217 int matcheof = 0, reverse = option_mask32 & FLAG_REVERSE, backwarn = 0; 218 /* Do we try "dummy" revert to check whether 219 * to silently skip this hunk? Used to implement -N. 220 */ 221 int dummy_revert = 0; 222 223 // Break doubly linked list so we can use singly linked traversal function. 224 TT.current_hunk->prev->next = NULL; 225 226 // Match EOF if there aren't as many ending context lines as beginning 227 for (plist = TT.current_hunk; plist; plist = plist->next) { 228 if (plist->data[0]==' ') matcheof++; 229 else matcheof = 0; 230 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); 231 } 232 matcheof = matcheof < TT.context; 233 234 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); 235 236 // Loop through input data searching for this hunk. Match all context 237 // lines and all lines to be removed until we've found the end of a 238 // complete hunk. 239 plist = TT.current_hunk; 240 buf = NULL; 241 if (TT.context) for (;;) { 242 char *data = xmalloc_reads(TT.filein, NULL, NULL); 243 244 TT.linenum++; 245 246 // Figure out which line of hunk to compare with next. (Skip lines 247 // of the hunk we'd be adding.) 248 while (plist && *plist->data == "+-"[reverse]) { 249 if (data && !strcmp(data, plist->data+1)) { 250 if (!backwarn) { 251 backwarn = TT.linenum; 252 if (option_mask32 & FLAG_IGNORE) { 253 dummy_revert = 1; 254 reverse ^= 1; 255 continue; 256 } 257 } 146 258 } 147 dst_stream = xfopen(new_filename, "w+"); 148 backup_filename = NULL; 149 } else { 150 backup_filename = xmalloc(strlen(new_filename) + 6); 151 strcpy(backup_filename, new_filename); 152 strcat(backup_filename, ".orig"); 153 if (rename(new_filename, backup_filename) == -1) { 154 bb_perror_msg_and_die("cannot create file %s", 155 backup_filename); 156 } 157 dst_stream = xfopen(new_filename, "w"); 158 } 159 160 if ((backup_filename == NULL) || file_doesnt_exist(original_filename)) { 161 src_stream = NULL; 162 } else { 163 if (strcmp(original_filename, new_filename) == 0) { 164 src_stream = xfopen(backup_filename, "r"); 165 } else { 166 src_stream = xfopen(original_filename, "r"); 167 } 168 } 169 170 printf("patching file %s\n", new_filename); 171 172 /* Handle each hunk */ 173 patch_line = xmalloc_fgets(patch_file); 174 while (patch_line) { 175 unsigned int count; 176 unsigned int src_beg_line; 177 unsigned int unused; 178 unsigned int hunk_offset_start = 0; 179 int hunk_error = 0; 180 181 /* This bit should be improved */ 182 if ((sscanf(patch_line, "@@ -%d,%d +%d,%d @@", &src_beg_line, &unused, &dest_beg_line, &unused) != 4) && 183 (sscanf(patch_line, "@@ -%d,%d +%d @@", &src_beg_line, &unused, &dest_beg_line) != 3) && 184 (sscanf(patch_line, "@@ -%d +%d,%d @@", &src_beg_line, &dest_beg_line, &unused) != 3)) { 185 /* No more hunks for this file */ 186 break; 187 } 188 free(patch_line); 189 hunk_count++; 190 191 if (src_beg_line && dest_beg_line) { 192 /* Copy unmodified lines upto start of hunk */ 193 /* src_beg_line will be 0 if its a new file */ 194 count = src_beg_line - src_cur_line; 195 if (copy_lines(src_stream, dst_stream, count) != count) { 196 bb_error_msg_and_die("bad src file"); 197 } 198 src_cur_line += count; 199 dest_cur_line += count; 200 copy_trailing_lines_flag = 1; 201 } 202 hunk_offset_start = src_cur_line; 203 204 while ((patch_line = xmalloc_fgets(patch_file)) != NULL) { 205 if ((*patch_line == '-') || (*patch_line == ' ')) { 206 char *src_line = NULL; 207 if (src_stream) { 208 src_line = xmalloc_fgets(src_stream); 209 if (!src_line) { 210 hunk_error++; 211 break; 212 } else { 213 src_cur_line++; 214 } 215 if (strcmp(src_line, patch_line + 1) != 0) { 216 bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start); 217 hunk_error++; 218 free(patch_line); 219 /* Probably need to find next hunk, etc... */ 220 /* but for now we just bail out */ 221 patch_line = NULL; 222 break; 223 } 224 free(src_line); 225 } 226 if (*patch_line == ' ') { 227 fputs(patch_line + 1, dst_stream); 228 dest_cur_line++; 229 } 230 } else if (*patch_line == '+') { 231 fputs(patch_line + 1, dst_stream); 232 dest_cur_line++; 233 } else { 259 plist = plist->next; 260 } 261 262 // Is this EOF? 263 if (!data) { 264 if (PATCH_DEBUG) fdprintf(2, "INEOF\n"); 265 266 // Does this hunk need to match EOF? 267 if (!plist && matcheof) break; 268 269 if (backwarn) 270 fdprintf(2,"Possibly reversed hunk %d at %ld\n", 271 TT.hunknum, TT.linenum); 272 273 // File ended before we found a place for this hunk. 274 fail_hunk(); 275 goto done; 276 } 277 278 if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); 279 check = dlist_add(&buf, data); 280 281 // Compare this line with next expected line of hunk. 282 // todo: teach the strcmp() to ignore whitespace. 283 284 // A match can fail because the next line doesn't match, or because 285 // we hit the end of a hunk that needed EOF, and this isn't EOF. 286 287 // If match failed, flush first line of buffered data and 288 // recheck buffered data for a new match until we find one or run 289 // out of buffer. 290 291 for (;;) { 292 if (!plist || strcmp(check->data, plist->data+1)) { 293 // Match failed. Write out first line of buffered data and 294 // recheck remaining buffered data for a new match. 295 296 if (PATCH_DEBUG) 297 fdprintf(2, "NOT: %s\n", plist->data); 298 299 TT.state = 3; 300 check = buf; 301 buf = buf->next; 302 check->prev->next = buf; 303 buf->prev = check->prev; 304 do_line(check); 305 plist = TT.current_hunk; 306 307 // If we've reached the end of the buffer without confirming a 308 // match, read more lines. 309 if (check == buf) { 310 buf = NULL; 234 311 break; 235 312 } 236 free(patch_line); 313 check = buf; 314 } else { 315 if (PATCH_DEBUG) 316 fdprintf(2, "MAYBE: %s\n", plist->data); 317 // This line matches. Advance plist, detect successful match. 318 plist = plist->next; 319 if (!plist && !matcheof) goto out; 320 check = check->next; 321 if (check == buf) break; 237 322 } 238 if (hunk_error) { 239 bad_hunk_count++; 323 } 324 } 325 out: 326 // We have a match. Emit changed data. 327 TT.state = "-+"[reverse ^ dummy_revert]; 328 dlist_free(TT.current_hunk, do_line); 329 TT.current_hunk = NULL; 330 TT.state = 1; 331 done: 332 if (buf) { 333 buf->prev->next = NULL; 334 dlist_free(buf, do_line); 335 } 336 337 return TT.state; 338 } 339 340 // Read a patch file and find hunks, opening/creating/deleting files. 341 // Call apply_one_hunk() on each hunk. 342 343 // state 0: Not in a hunk, look for +++. 344 // state 1: Found +++ file indicator, look for @@ 345 // state 2: In hunk: counting initial context lines 346 // state 3: In hunk: getting body 347 348 int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 349 int patch_main(int argc UNUSED_PARAM, char **argv) 350 { 351 int opts; 352 int reverse, state = 0; 353 char *oldname = NULL, *newname = NULL; 354 char *opt_p, *opt_i; 355 356 INIT_TT(); 357 358 opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); 359 argv += optind; 360 reverse = opts & FLAG_REVERSE; 361 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! 362 TT.filein = TT.fileout = -1; 363 if (opts & FLAG_INPUT) { 364 xmove_fd(xopen_stdin(opt_i), STDIN_FILENO); 365 } else { 366 if (argv[0] && argv[1]) { 367 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); 368 } 369 } 370 if (argv[0]) { 371 oldname = xstrdup(argv[0]); 372 newname = xstrdup(argv[0]); 373 } 374 375 // Loop through the lines in the patch 376 for(;;) { 377 char *patchline; 378 379 patchline = xmalloc_fgetline(stdin); 380 if (!patchline) break; 381 382 // Other versions of patch accept damaged patches, 383 // so we need to also. 384 if (!*patchline) { 385 free(patchline); 386 patchline = xstrdup(" "); 387 } 388 389 // Are we assembling a hunk? 390 if (state >= 2) { 391 if (*patchline==' ' || *patchline=='+' || *patchline=='-') { 392 dlist_add(&TT.current_hunk, patchline); 393 394 if (*patchline != '+') TT.oldlen--; 395 if (*patchline != '-') TT.newlen--; 396 397 // Context line? 398 if (*patchline==' ' && state==2) TT.context++; 399 else state=3; 400 401 // If we've consumed all expected hunk lines, apply the hunk. 402 403 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); 404 continue; 240 405 } 241 } 242 243 /* Cleanup last patched file */ 244 if (copy_trailing_lines_flag) { 245 copy_lines(src_stream, dst_stream, -1); 246 } 247 if (src_stream) { 248 fclose(src_stream); 249 } 250 if (dst_stream) { 251 fclose(dst_stream); 252 } 253 if (bad_hunk_count) { 254 if (!ret) { 255 ret = 1; 406 fail_hunk(); 407 state = 0; 408 continue; 409 } 410 411 // Open a new file? 412 if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { 413 char *s, **name = reverse ? &newname : &oldname; 414 int i; 415 416 if (*patchline == '+') { 417 name = reverse ? &oldname : &newname; 418 state = 1; 256 419 } 257 bb_error_msg("%d out of %d hunk FAILED", bad_hunk_count, hunk_count); 258 } else { 259 /* It worked, we can remove the backup */ 260 if (backup_filename) { 261 unlink(backup_filename); 420 421 finish_oldfile(); 422 423 if (!argv[0]) { 424 free(*name); 425 // Trim date from end of filename (if any). We don't care. 426 for (s = patchline+4; *s && *s!='\t'; s++) 427 if (*s=='\\' && s[1]) s++; 428 i = atoi(s); 429 if (i>1900 && i<=1970) 430 *name = xstrdup("/dev/null"); 431 else { 432 *s = 0; 433 *name = xstrdup(patchline+4); 434 } 262 435 } 263 if ((dest_cur_line == 0) || (dest_beg_line == 0)) { 264 /* The new patched file is empty, remove it */ 265 xunlink(new_filename); 266 if (strcmp(new_filename, original_filename) != 0) 267 xunlink(original_filename); 436 437 // We defer actually opening the file because svn produces broken 438 // patches that don't signal they want to create a new file the 439 // way the patch man page says, so you have to read the first hunk 440 // and _guess_. 441 442 // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ 443 // but a missing ,value means the value is 1. 444 } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { 445 int i; 446 char *s = patchline+4; 447 448 // Read oldline[,oldlen] +newline[,newlen] 449 450 TT.oldlen = TT.newlen = 1; 451 TT.oldline = strtol(s, &s, 10); 452 if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); 453 TT.newline = strtol(s+2, &s, 10); 454 if (*s == ',') TT.newlen = strtol(s+1, &s, 10); 455 456 TT.context = 0; 457 state = 2; 458 459 // If this is the first hunk, open the file. 460 if (TT.filein == -1) { 461 int oldsum, newsum, empty = 0; 462 char *name; 463 464 oldsum = TT.oldline + TT.oldlen; 465 newsum = TT.newline + TT.newlen; 466 467 name = reverse ? oldname : newname; 468 469 // We're deleting oldname if new file is /dev/null (before -p) 470 // or if new hunk is empty (zero context) after patching 471 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) 472 { 473 name = reverse ? newname : oldname; 474 empty++; 475 } 476 477 // handle -p path truncation. 478 for (i=0, s = name; *s;) { 479 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; 480 if (*(s++)=='/') { 481 name = s; 482 i++; 483 } 484 } 485 486 if (empty) { 487 // File is empty after the patches have been applied 488 state = 0; 489 if (option_mask32 & FLAG_RMEMPTY) { 490 // If flag -E or --remove-empty-files is set 491 printf("removing %s\n", name); 492 xunlink(name); 493 } else { 494 printf("patching file %s\n", name); 495 xclose(xopen(name, O_WRONLY | O_TRUNC)); 496 } 497 // If we've got a file to open, do so. 498 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { 499 struct stat statbuf; 500 501 // If the old file was null, we're creating a new one. 502 if (!strcmp(oldname, "/dev/null") || !oldsum) { 503 printf("creating %s\n", name); 504 s = strrchr(name, '/'); 505 if (s) { 506 *s = 0; 507 bb_make_directory(name, -1, FILEUTILS_RECUR); 508 *s = '/'; 509 } 510 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); 511 } else { 512 printf("patching file %s\n", name); 513 TT.filein = xopen(name, O_RDONLY); 514 } 515 516 TT.tempname = xasprintf("%sXXXXXX", name); 517 TT.fileout = xmkstemp(TT.tempname); 518 // Set permissions of output file 519 fstat(TT.filein, &statbuf); 520 fchmod(TT.fileout, statbuf.st_mode); 521 522 TT.linenum = 0; 523 TT.hunknum = 0; 524 } 268 525 } 269 } 270 } 271 272 /* 0 = SUCCESS 273 * 1 = Some hunks failed 274 * 2 = More serious problems 275 */ 276 return ret; 277 } 526 527 TT.hunknum++; 528 529 continue; 530 } 531 532 // If we didn't continue above, discard this line. 533 free(patchline); 534 } 535 536 finish_oldfile(); 537 538 if (ENABLE_FEATURE_CLEAN_UP) { 539 free(oldname); 540 free(newname); 541 } 542 543 return TT.exitval; 544 }
Note:
See TracChangeset
for help on using the changeset viewer.