1 /* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS source distribution. 7 * 8 * Patch 9 * 10 * Create a Larry Wall format "patch" file between a previous release and the 11 * current head of a module, or between two releases. Can specify the 12 * release as either a date or a revision number. 13 */ 14 15 #include <assert.h> 16 #include "cvs.h" 17 #include "getline.h" 18 19 static RETSIGTYPE patch_cleanup PROTO((void)); 20 static Dtype patch_dirproc PROTO ((void *callerdat, char *dir, 21 char *repos, char *update_dir, 22 List *entries)); 23 static int patch_fileproc PROTO ((void *callerdat, struct file_info *finfo)); 24 static int patch_proc PROTO((int argc, char **argv, char *xwhere, 25 char *mwhere, char *mfile, int shorten, 26 int local_specified, char *mname, char *msg)); 27 28 static int force_tag_match = 1; 29 static int patch_short = 0; 30 static int toptwo_diffs = 0; 31 static int local = 0; 32 static char *options = NULL; 33 static char *rev1 = NULL; 34 static int rev1_validated = 0; 35 static char *rev2 = NULL; 36 static int rev2_validated = 0; 37 static char *date1 = NULL; 38 static char *date2 = NULL; 39 static char *tmpfile1 = NULL; 40 static char *tmpfile2 = NULL; 41 static char *tmpfile3 = NULL; 42 static int unidiff = 0; 43 44 static const char *const patch_usage[] = 45 { 46 "Usage: %s %s [-flR] [-c|-u] [-s|-t] [-V %%d]\n", 47 " -r rev|-D date [-r rev2 | -D date2] modules...\n", 48 "\t-f\tForce a head revision match if tag/date not found.\n", 49 "\t-l\tLocal directory only, not recursive\n", 50 "\t-R\tProcess directories recursively.\n", 51 "\t-c\tContext diffs (default)\n", 52 "\t-u\tUnidiff format.\n", 53 "\t-s\tShort patch - one liner per file.\n", 54 "\t-t\tTop two diffs - last change made to the file.\n", 55 "\t-D date\tDate.\n", 56 "\t-r rev\tRevision - symbolic or numeric.\n", 57 "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n", 58 "(Specify the --help global option for a list of other help options)\n", 59 NULL 60 }; 61 62 int 63 patch (argc, argv) 64 int argc; 65 char **argv; 66 { 67 register int i; 68 int c; 69 int err = 0; 70 DBM *db; 71 72 if (argc == -1) 73 usage (patch_usage); 74 75 optind = 0; 76 while ((c = getopt (argc, argv, "+V:k:cuftsQqlRD:r:")) != -1) 77 { 78 switch (c) 79 { 80 case 'Q': 81 case 'q': 82 #ifdef SERVER_SUPPORT 83 /* The CVS 1.5 client sends these options (in addition to 84 Global_option requests), so we must ignore them. */ 85 if (!server_active) 86 #endif 87 error (1, 0, 88 "-q or -Q must be specified before \"%s\"", 89 command_name); 90 break; 91 case 'f': 92 force_tag_match = 0; 93 break; 94 case 'l': 95 local = 1; 96 break; 97 case 'R': 98 local = 0; 99 break; 100 case 't': 101 toptwo_diffs = 1; 102 break; 103 case 's': 104 patch_short = 1; 105 break; 106 case 'D': 107 if (rev2 != NULL || date2 != NULL) 108 error (1, 0, 109 "no more than two revisions/dates can be specified"); 110 if (rev1 != NULL || date1 != NULL) 111 date2 = Make_Date (optarg); 112 else 113 date1 = Make_Date (optarg); 114 break; 115 case 'r': 116 if (rev2 != NULL || date2 != NULL) 117 error (1, 0, 118 "no more than two revisions/dates can be specified"); 119 if (rev1 != NULL || date1 != NULL) 120 rev2 = optarg; 121 else 122 rev1 = optarg; 123 break; 124 case 'k': 125 if (options) 126 free (options); 127 options = RCS_check_kflag (optarg); 128 break; 129 case 'V': 130 /* This option is pretty seriously broken: 131 1. It is not clear what it does (does it change keyword 132 expansion behavior? If so, how? Or does it have 133 something to do with what version of RCS we are using? 134 Or the format we write RCS files in?). 135 2. Because both it and -k use the options variable, 136 specifying both -V and -k doesn't work. 137 3. At least as of CVS 1.9, it doesn't work (failed 138 assertion in RCS_checkout where it asserts that options 139 starts with -k). Few people seem to be complaining. 140 In the future (perhaps the near future), I have in mind 141 removing it entirely, and updating NEWS and cvs.texinfo, 142 but in case it is a good idea to give people more time 143 to complain if they would miss it, I'll just add this 144 quick and dirty error message for now. */ 145 error (1, 0, 146 "the -V option is obsolete and should not be used"); 147 #if 0 148 if (atoi (optarg) <= 0) 149 error (1, 0, "must specify a version number to -V"); 150 if (options) 151 free (options); 152 options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */ 153 (void) sprintf (options, "-V%s", optarg); 154 #endif 155 break; 156 case 'u': 157 unidiff = 1; /* Unidiff */ 158 break; 159 case 'c': /* Context diff */ 160 unidiff = 0; 161 break; 162 case '?': 163 default: 164 usage (patch_usage); 165 break; 166 } 167 } 168 argc -= optind; 169 argv += optind; 170 171 /* Sanity checks */ 172 if (argc < 1) 173 usage (patch_usage); 174 175 if (toptwo_diffs && patch_short) 176 error (1, 0, "-t and -s options are mutually exclusive"); 177 if (toptwo_diffs && (date1 != NULL || date2 != NULL || 178 rev1 != NULL || rev2 != NULL)) 179 error (1, 0, "must not specify revisions/dates with -t option!"); 180 181 if (!toptwo_diffs && (date1 == NULL && date2 == NULL && 182 rev1 == NULL && rev2 == NULL)) 183 error (1, 0, "must specify at least one revision/date!"); 184 if (date1 != NULL && date2 != NULL) 185 if (RCS_datecmp (date1, date2) >= 0) 186 error (1, 0, "second date must come after first date!"); 187 188 /* if options is NULL, make it a NULL string */ 189 if (options == NULL) 190 options = xstrdup (""); 191 192 #ifdef CLIENT_SUPPORT 193 if (current_parsed_root->isremote) 194 { 195 /* We're the client side. Fire up the remote server. */ 196 start_server (); 197 198 ign_setup (); 199 200 if (local) 201 send_arg("-l"); 202 if (!force_tag_match) 203 send_arg("-f"); 204 if (toptwo_diffs) 205 send_arg("-t"); 206 if (patch_short) 207 send_arg("-s"); 208 if (unidiff) 209 send_arg("-u"); 210 211 if (rev1) 212 option_with_arg ("-r", rev1); 213 if (date1) 214 client_senddate (date1); 215 if (rev2) 216 option_with_arg ("-r", rev2); 217 if (date2) 218 client_senddate (date2); 219 if (options[0] != '\0') 220 send_arg (options); 221 222 { 223 int i; 224 for (i = 0; i < argc; ++i) 225 send_arg (argv[i]); 226 } 227 228 send_to_server ("rdiff\012", 0); 229 return get_responses_and_close (); 230 } 231 #endif 232 233 /* clean up if we get a signal */ 234 #ifdef SIGABRT 235 (void) SIG_register (SIGABRT, patch_cleanup); 236 #endif 237 #ifdef SIGHUP 238 (void) SIG_register (SIGHUP, patch_cleanup); 239 #endif 240 #ifdef SIGINT 241 (void) SIG_register (SIGINT, patch_cleanup); 242 #endif 243 #ifdef SIGQUIT 244 (void) SIG_register (SIGQUIT, patch_cleanup); 245 #endif 246 #ifdef SIGPIPE 247 (void) SIG_register (SIGPIPE, patch_cleanup); 248 #endif 249 #ifdef SIGTERM 250 (void) SIG_register (SIGTERM, patch_cleanup); 251 #endif 252 253 db = open_module (); 254 for (i = 0; i < argc; i++) 255 err += do_module (db, argv[i], PATCH, "Patching", patch_proc, 256 (char *) NULL, 0, 0, 0, 0, (char *) NULL); 257 close_module (db); 258 free (options); 259 patch_cleanup (); 260 return (err); 261 } 262 263 /* 264 * callback proc for doing the real work of patching 265 */ 266 /* ARGSUSED */ 267 static int 268 patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, 269 mname, msg) 270 int argc; 271 char **argv; 272 char *xwhere; 273 char *mwhere; 274 char *mfile; 275 int shorten; 276 int local_specified; 277 char *mname; 278 char *msg; 279 { 280 char *myargv[2]; 281 int err = 0; 282 int which; 283 char *repository; 284 char *where; 285 286 repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) 287 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); 288 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); 289 where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) 290 + 1); 291 (void) strcpy (where, argv[0]); 292 293 /* if mfile isn't null, we need to set up to do only part of the module */ 294 if (mfile != NULL) 295 { 296 char *cp; 297 char *path; 298 299 /* if the portion of the module is a path, put the dir part on repos */ 300 if ((cp = strrchr (mfile, '/')) != NULL) 301 { 302 *cp = '\0'; 303 (void) strcat (repository, "/"); 304 (void) strcat (repository, mfile); 305 (void) strcat (where, "/"); 306 (void) strcat (where, mfile); 307 mfile = cp + 1; 308 } 309 310 /* take care of the rest */ 311 path = xmalloc (strlen (repository) + strlen (mfile) + 2); 312 (void) sprintf (path, "%s/%s", repository, mfile); 313 if (isdir (path)) 314 { 315 /* directory means repository gets the dir tacked on */ 316 (void) strcpy (repository, path); 317 (void) strcat (where, "/"); 318 (void) strcat (where, mfile); 319 } 320 else 321 { 322 myargv[0] = argv[0]; 323 myargv[1] = mfile; 324 argc = 2; 325 argv = myargv; 326 } 327 free (path); 328 } 329 330 /* cd to the starting repository */ 331 if ( CVS_CHDIR (repository) < 0) 332 { 333 error (0, errno, "cannot chdir to %s", repository); 334 free (repository); 335 return (1); 336 } 337 free (repository); 338 339 if (force_tag_match) 340 which = W_REPOS | W_ATTIC; 341 else 342 which = W_REPOS; 343 344 if (rev1 != NULL && !rev1_validated) 345 { 346 tag_check_valid (rev1, argc - 1, argv + 1, local, 0, NULL); 347 rev1_validated = 1; 348 } 349 if (rev2 != NULL && !rev2_validated) 350 { 351 tag_check_valid (rev2, argc - 1, argv + 1, local, 0, NULL); 352 rev2_validated = 1; 353 } 354 355 /* start the recursion processor */ 356 err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL, patch_dirproc, 357 (DIRLEAVEPROC) NULL, NULL, 358 argc - 1, argv + 1, local, 359 which, 0, 1, where, 1); 360 free (where); 361 362 return (err); 363 } 364 365 /* 366 * Called to examine a particular RCS file, as appropriate with the options 367 * that were set above. 368 */ 369 /* ARGSUSED */ 370 static int 371 patch_fileproc (callerdat, finfo) 372 void *callerdat; 373 struct file_info *finfo; 374 { 375 struct utimbuf t; 376 char *vers_tag, *vers_head; 377 char *rcs = NULL; 378 char *rcs_orig = NULL; 379 RCSNode *rcsfile; 380 FILE *fp1, *fp2, *fp3; 381 int ret = 0; 382 int isattic = 0; 383 int retcode = 0; 384 char *file1; 385 char *file2; 386 char *strippath; 387 char *line1, *line2; 388 size_t line1_chars_allocated; 389 size_t line2_chars_allocated; 390 char *cp1, *cp2; 391 FILE *fp; 392 int line_length; 393 394 line1 = NULL; 395 line1_chars_allocated = 0; 396 line2 = NULL; 397 line2_chars_allocated = 0; 398 399 /* find the parsed rcs file */ 400 if ((rcsfile = finfo->rcs) == NULL) 401 { 402 ret = 1; 403 goto out2; 404 } 405 if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) 406 isattic = 1; 407 408 rcs_orig = rcs = xmalloc (strlen (finfo->file) + sizeof (RCSEXT) + 5); 409 (void) sprintf (rcs, "%s%s", finfo->file, RCSEXT); 410 411 /* if vers_head is NULL, may have been removed from the release */ 412 if (isattic && rev2 == NULL && date2 == NULL) 413 vers_head = NULL; 414 else 415 { 416 vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, 417 (int *) NULL); 418 if (vers_head != NULL && RCS_isdead (rcsfile, vers_head)) 419 { 420 free (vers_head); 421 vers_head = NULL; 422 } 423 } 424 425 if (toptwo_diffs) 426 { 427 if (vers_head == NULL) 428 { 429 ret = 1; 430 goto out2; 431 } 432 433 if (!date1) 434 date1 = xmalloc (MAXDATELEN); 435 *date1 = '\0'; 436 if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == -1) 437 { 438 if (!really_quiet) 439 error (0, 0, "cannot find date in rcs file %s revision %s", 440 rcs, vers_head); 441 ret = 1; 442 goto out2; 443 } 444 } 445 vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, 446 (int *) NULL); 447 if (vers_tag != NULL && RCS_isdead (rcsfile, vers_tag)) 448 { 449 free (vers_tag); 450 vers_tag = NULL; 451 } 452 453 if (vers_tag == NULL && vers_head == NULL) 454 { 455 /* Nothing known about specified revs. */ 456 ret = 0; 457 goto out2; 458 } 459 460 if (vers_tag && vers_head && strcmp (vers_head, vers_tag) == 0) 461 { 462 /* Not changed between releases. */ 463 ret = 0; 464 goto out2; 465 } 466 467 if (patch_short) 468 { 469 cvs_output ("File ", 0); 470 cvs_output (finfo->fullname, 0); 471 if (vers_tag == NULL) 472 { 473 cvs_output (" is new; current revision ", 0); 474 cvs_output (vers_head, 0); 475 cvs_output ("\n", 1); 476 } 477 else if (vers_head == NULL) 478 { 479 cvs_output (" is removed; not included in ", 0); 480 if (rev2 != NULL) 481 { 482 cvs_output ("release tag ", 0); 483 cvs_output (rev2, 0); 484 } 485 else if (date2 != NULL) 486 { 487 cvs_output ("release date ", 0); 488 cvs_output (date2, 0); 489 } 490 else 491 cvs_output ("current release", 0); 492 cvs_output ("\n", 1); 493 } 494 else 495 { 496 cvs_output (" changed from revision ", 0); 497 cvs_output (vers_tag, 0); 498 cvs_output (" to ", 0); 499 cvs_output (vers_head, 0); 500 cvs_output ("\n", 1); 501 } 502 ret = 0; 503 goto out2; 504 } 505 506 /* Create 3 empty files. I'm not really sure there is any advantage 507 * to doing so now rather than just waiting until later. 508 * 509 * There is - cvs_temp_file opens the file so that it can guarantee that 510 * we have exclusive write access to the file. Unfortunately we spoil that 511 * by closing it and reopening it again. Of course any better solution 512 * requires that the RCS functions accept open file pointers rather than 513 * simple file names. 514 */ 515 if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL) 516 { 517 error (0, errno, "cannot create temporary file %s", tmpfile1); 518 ret = 1; 519 goto out; 520 } 521 else 522 if (fclose (fp1) < 0) 523 error (0, errno, "warning: cannot close %s", tmpfile1); 524 if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL) 525 { 526 error (0, errno, "cannot create temporary file %s", tmpfile2); 527 ret = 1; 528 goto out; 529 } 530 else 531 if (fclose (fp2) < 0) 532 error (0, errno, "warning: cannot close %s", tmpfile2); 533 if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL) 534 { 535 error (0, errno, "cannot create temporary file %s", tmpfile3); 536 ret = 1; 537 goto out; 538 } 539 else 540 if (fclose (fp3) < 0) 541 error (0, errno, "warning: cannot close %s", tmpfile3); 542 543 if (vers_tag != NULL) 544 { 545 retcode = RCS_checkout (rcsfile, (char *) NULL, vers_tag, 546 rev1, options, tmpfile1, 547 (RCSCHECKOUTPROC) NULL, (void *) NULL); 548 if (retcode != 0) 549 { 550 error (0, 0, 551 "cannot check out revision %s of %s", vers_tag, rcs); 552 ret = 1; 553 goto out; 554 } 555 memset ((char *) &t, 0, sizeof (t)); 556 if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag, 557 (char *) 0, 0)) != -1) 558 /* I believe this timestamp only affects the dates in our diffs, 559 and therefore should be on the server, not the client. */ 560 (void) utime (tmpfile1, &t); 561 } 562 else if (toptwo_diffs) 563 { 564 ret = 1; 565 goto out; 566 } 567 if (vers_head != NULL) 568 { 569 retcode = RCS_checkout (rcsfile, (char *) NULL, vers_head, 570 rev2, options, tmpfile2, 571 (RCSCHECKOUTPROC) NULL, (void *) NULL); 572 if (retcode != 0) 573 { 574 error (0, 0, 575 "cannot check out revision %s of %s", vers_head, rcs); 576 ret = 1; 577 goto out; 578 } 579 if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head, 580 (char *) 0, 0)) != -1) 581 /* I believe this timestamp only affects the dates in our diffs, 582 and therefore should be on the server, not the client. */ 583 (void) utime (tmpfile2, &t); 584 } 585 586 switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, unidiff ? "-u" : "-c", tmpfile3)) 587 { 588 case -1: /* fork/wait failure */ 589 error (1, errno, "fork for diff failed on %s", rcs); 590 break; 591 case 0: /* nothing to do */ 592 break; 593 case 1: 594 /* 595 * The two revisions are really different, so read the first two 596 * lines of the diff output file, and munge them to include more 597 * reasonable file names that "patch" will understand. 598 */ 599 600 /* Output an "Index:" line for patch to use */ 601 cvs_output ("Index: ", 0); 602 cvs_output (finfo->fullname, 0); 603 cvs_output ("\n", 1); 604 605 fp = open_file (tmpfile3, "r"); 606 if (get_line (&line1, &line1_chars_allocated, fp) < 0 || 607 get_line (&line2, &line2_chars_allocated, fp) < 0) 608 { 609 if (feof (fp)) 610 error (0, 0, "\ 611 failed to read diff file header %s for %s: end of file", tmpfile3, rcs); 612 else 613 error (0, errno, 614 "failed to read diff file header %s for %s", 615 tmpfile3, rcs); 616 ret = 1; 617 if (fclose (fp) < 0) 618 error (0, errno, "error closing %s", tmpfile3); 619 goto out; 620 } 621 if (!unidiff) 622 { 623 if (strncmp (line1, "*** ", 4) != 0 || 624 strncmp (line2, "--- ", 4) != 0 || 625 (cp1 = strchr (line1, '\t')) == NULL || 626 (cp2 = strchr (line2, '\t')) == NULL) 627 { 628 error (0, 0, "invalid diff header for %s", rcs); 629 ret = 1; 630 if (fclose (fp) < 0) 631 error (0, errno, "error closing %s", tmpfile3); 632 goto out; 633 } 634 } 635 else 636 { 637 if (strncmp (line1, "--- ", 4) != 0 || 638 strncmp (line2, "+++ ", 4) != 0 || 639 (cp1 = strchr (line1, '\t')) == NULL || 640 (cp2 = strchr (line2, '\t')) == NULL) 641 { 642 error (0, 0, "invalid unidiff header for %s", rcs); 643 ret = 1; 644 if (fclose (fp) < 0) 645 error (0, errno, "error closing %s", tmpfile3); 646 goto out; 647 } 648 } 649 assert (current_parsed_root != NULL); 650 assert (current_parsed_root->directory != NULL); 651 { 652 strippath = xmalloc (strlen (current_parsed_root->directory) + 2); 653 (void) sprintf (strippath, "%s/", current_parsed_root->directory); 654 } 655 /*else 656 strippath = xstrdup (REPOS_STRIP); */ 657 if (strncmp (rcs, strippath, strlen (strippath)) == 0) 658 rcs += strlen (strippath); 659 free (strippath); 660 if (vers_tag != NULL) 661 { 662 file1 = xmalloc (strlen (finfo->fullname) 663 + strlen (vers_tag) 664 + 10); 665 (void) sprintf (file1, "%s:%s", finfo->fullname, vers_tag); 666 } 667 else 668 { 669 file1 = xstrdup (DEVNULL); 670 } 671 file2 = xmalloc (strlen (finfo->fullname) 672 + (vers_head != NULL ? strlen (vers_head) : 10) 673 + 10); 674 (void) sprintf (file2, "%s:%s", finfo->fullname, 675 vers_head ? vers_head : "removed"); 676 677 /* Note that the string "diff" is specified by POSIX (for -c) 678 and is part of the diff output format, not the name of a 679 program. */ 680 if (unidiff) 681 { 682 cvs_output ("diff -u ", 0); 683 cvs_output (file1, 0); 684 cvs_output (" ", 1); 685 cvs_output (file2, 0); 686 cvs_output ("\n", 1); 687 688 cvs_output ("--- ", 0); 689 cvs_output (file1, 0); 690 cvs_output (cp1, 0); 691 cvs_output ("+++ ", 0); 692 } 693 else 694 { 695 cvs_output ("diff -c ", 0); 696 cvs_output (file1, 0); 697 cvs_output (" ", 1); 698 cvs_output (file2, 0); 699 cvs_output ("\n", 1); 700 701 cvs_output ("*** ", 0); 702 cvs_output (file1, 0); 703 cvs_output (cp1, 0); 704 cvs_output ("--- ", 0); 705 } 706 707 cvs_output (finfo->fullname, 0); 708 cvs_output (cp2, 0); 709 710 /* spew the rest of the diff out */ 711 while ((line_length 712 = get_line (&line1, &line1_chars_allocated, fp)) 713 >= 0) 714 cvs_output (line1, 0); 715 if (line_length < 0 && !feof (fp)) 716 error (0, errno, "cannot read %s", tmpfile3); 717 718 if (fclose (fp) < 0) 719 error (0, errno, "cannot close %s", tmpfile3); 720 free (file1); 721 free (file2); 722 break; 723 default: 724 error (0, 0, "diff failed for %s", finfo->fullname); 725 } 726 out: 727 if (line1) 728 free (line1); 729 if (line2) 730 free (line2); 731 if (CVS_UNLINK (tmpfile1) < 0) 732 error (0, errno, "cannot unlink %s", tmpfile1); 733 if (CVS_UNLINK (tmpfile2) < 0) 734 error (0, errno, "cannot unlink %s", tmpfile2); 735 if (CVS_UNLINK (tmpfile3) < 0) 736 error (0, errno, "cannot unlink %s", tmpfile3); 737 free (tmpfile1); 738 free (tmpfile2); 739 free (tmpfile3); 740 tmpfile1 = tmpfile2 = tmpfile3 = NULL; 741 742 out2: 743 if (vers_tag != NULL) 744 free (vers_tag); 745 if (vers_head != NULL) 746 free (vers_head); 747 if (rcs_orig) 748 free (rcs_orig); 749 return (ret); 750 } 751 752 /* 753 * Print a warm fuzzy message 754 */ 755 /* ARGSUSED */ 756 static Dtype 757 patch_dirproc (callerdat, dir, repos, update_dir, entries) 758 void *callerdat; 759 char *dir; 760 char *repos; 761 char *update_dir; 762 List *entries; 763 { 764 if (!quiet) 765 error (0, 0, "Diffing %s", update_dir); 766 return (R_PROCESS); 767 } 768 769 /* 770 * Clean up temporary files 771 */ 772 static RETSIGTYPE 773 patch_cleanup () 774 { 775 /* Note that the checks for existence_error are because we are 776 called from a signal handler, without SIG_begincrsect, so 777 we don't know whether the files got created. */ 778 779 if (tmpfile1 != NULL) 780 { 781 if (unlink_file (tmpfile1) < 0 782 && !existence_error (errno)) 783 error (0, errno, "cannot remove %s", tmpfile1); 784 free (tmpfile1); 785 } 786 if (tmpfile2 != NULL) 787 { 788 if (unlink_file (tmpfile2) < 0 789 && !existence_error (errno)) 790 error (0, errno, "cannot remove %s", tmpfile2); 791 free (tmpfile2); 792 } 793 if (tmpfile3 != NULL) 794 { 795 if (unlink_file (tmpfile3) < 0 796 && !existence_error (errno)) 797 error (0, errno, "cannot remove %s", tmpfile3); 798 free (tmpfile3); 799 } 800 tmpfile1 = tmpfile2 = tmpfile3 = NULL; 801 } 802