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
patch(argc,argv)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
patch_proc(argc,argv,xwhere,mwhere,mfile,shorten,local_specified,mname,msg)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
patch_fileproc(callerdat,finfo)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
patch_dirproc(callerdat,dir,repos,update_dir,entries)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
patch_cleanup()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