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