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