GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/diff.c Lines: 109 355 30.7 %
Date: 2017-11-07 Branches: 58 250 23.2 %

Line Branch Exec Source
1
/*	$OpenBSD: diff.c,v 1.163 2017/06/01 08:08:24 joris Exp $	*/
2
/*
3
 * Copyright (c) 2008 Tobias Stoeckmann <tobias@openbsd.org>
4
 * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/stat.h>
20
#include <sys/time.h>
21
22
#include <errno.h>
23
#include <fcntl.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <time.h>
27
#include <unistd.h>
28
29
#include "cvs.h"
30
#include "diff.h"
31
#include "remote.h"
32
33
void	cvs_diff_local(struct cvs_file *);
34
35
static int	 dflags = 0;
36
static int	 Nflag = 0;
37
static int	 force_head = 0;
38
static char	*koptstr;
39
static char	*rev1 = NULL;
40
static char	*rev2 = NULL;
41
static time_t	 date1 = -1;
42
static time_t	 date2 = -1;
43
static char	*dateflag1 = NULL;
44
static char	*dateflag2 = NULL;
45
46
struct cvs_cmd cvs_cmd_diff = {
47
	CVS_OP_DIFF, CVS_USE_WDIR, "diff",
48
	{ "di", "dif" },
49
	"Show differences between revisions",
50
	"[-abcdilNnpRuw] [[-D date] [-r rev] [-D date2 | -r rev2]] "
51
	"[-k mode] [file ...]",
52
	"abcfC:dD:ik:lNnpr:RuU:w",
53
	NULL,
54
	cvs_diff
55
};
56
57
struct cvs_cmd cvs_cmd_rdiff = {
58
	CVS_OP_RDIFF, 0, "rdiff",
59
	{ "patch", "pa" },
60
	"Show differences between revisions",
61
	"[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev\n"
62
	"[-D date2 | -r rev2] [-k mode] module ...",
63
	"cfD:k:lr:RuV:",
64
	NULL,
65
	cvs_diff
66
};
67
68
int
69
cvs_diff(int argc, char **argv)
70
{
71
	int ch, flags;
72
4
	char *arg = ".";
73
2
	const char *errstr;
74
2
	struct cvs_recursion cr;
75
76
	flags = CR_RECURSE_DIRS;
77
2
	strlcpy(diffargs, cvs_cmdop == CVS_OP_DIFF ? "diff" : "rdiff",
78
	    sizeof(diffargs));
79
80
6
	while ((ch = getopt(argc, argv, cvs_cmdop == CVS_OP_DIFF ?
81
2
	    cvs_cmd_diff.cmd_opts : cvs_cmd_rdiff.cmd_opts)) != -1) {
82
		switch (ch) {
83
		case 'a':
84
			strlcat(diffargs, " -a", sizeof(diffargs));
85
			dflags |= D_FORCEASCII;
86
			break;
87
		case 'b':
88
			strlcat(diffargs, " -b", sizeof(diffargs));
89
			dflags |= D_FOLDBLANKS;
90
			break;
91
		case 'c':
92
			strlcat(diffargs, " -c", sizeof(diffargs));
93
			diff_format = D_CONTEXT;
94
			break;
95
		case 'C':
96
			diff_context = strtonum(optarg, 0, INT_MAX, &errstr);
97
			if (errstr != NULL)
98
				fatal("context lines %s: %s", errstr, optarg);
99
			strlcat(diffargs, " -C ", sizeof(diffargs));
100
			strlcat(diffargs, optarg, sizeof(diffargs));
101
			diff_format = D_CONTEXT;
102
			break;
103
		case 'd':
104
			strlcat(diffargs, " -d", sizeof(diffargs));
105
			dflags |= D_MINIMAL;
106
			break;
107
		case 'D':
108
			if (date1 == -1 && rev1 == NULL) {
109
				if ((date1 = date_parse(optarg)) == -1)
110
					fatal("invalid date: %s", optarg);
111
				dateflag1 = optarg;
112
			} else if (date2 == -1 && rev2 == NULL) {
113
				if ((date2 = date_parse(optarg)) == -1)
114
					fatal("invalid date: %s", optarg);
115
				dateflag2 = optarg;
116
			} else {
117
				fatal("no more than 2 revisions/dates can"
118
				    " be specified");
119
			}
120
			break;
121
		case 'f':
122
			force_head = 1;
123
			break;
124
		case 'i':
125
			strlcat(diffargs, " -i", sizeof(diffargs));
126
			dflags |= D_IGNORECASE;
127
			break;
128
		case 'k':
129
			koptstr = optarg;
130
			kflag = rcs_kflag_get(koptstr);
131
			if (RCS_KWEXP_INVAL(kflag)) {
132
				cvs_log(LP_ERR,
133
				    "invalid RCS keyword expansion mode");
134
				fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
135
				    cvs_cmd_diff.cmd_synopsis :
136
				    cvs_cmd_rdiff.cmd_synopsis);
137
			}
138
			break;
139
		case 'l':
140
			flags &= ~CR_RECURSE_DIRS;
141
			break;
142
		case 'n':
143
			strlcat(diffargs, " -n", sizeof(diffargs));
144
			diff_format = D_RCSDIFF;
145
			break;
146
		case 'N':
147
			strlcat(diffargs, " -N", sizeof(diffargs));
148
			Nflag = 1;
149
			break;
150
		case 'p':
151
			strlcat(diffargs, " -p", sizeof(diffargs));
152
			dflags |= D_PROTOTYPE;
153
			break;
154
		case 'R':
155
			flags |= CR_RECURSE_DIRS;
156
			break;
157
		case 'r':
158
			if (date1 == -1 && rev1 == NULL) {
159
				rev1 = optarg;
160
			} else if (date2 == -1 && rev2 == NULL) {
161
				rev2 = optarg;
162
			} else {
163
				fatal("no more than 2 revisions/dates can"
164
				    " be specified");
165
			}
166
			break;
167
		case 't':
168
			strlcat(diffargs, " -t", sizeof(diffargs));
169
			dflags |= D_EXPANDTABS;
170
			break;
171
		case 'u':
172
			strlcat(diffargs, " -u", sizeof(diffargs));
173
			diff_format = D_UNIFIED;
174
			break;
175
		case 'U':
176
			diff_context = strtonum(optarg, 0, INT_MAX, &errstr);
177
			if (errstr != NULL)
178
				fatal("context lines %s: %s", errstr, optarg);
179
			strlcat(diffargs, " -U ", sizeof(diffargs));
180
			strlcat(diffargs, optarg, sizeof(diffargs));
181
			diff_format = D_UNIFIED;
182
			break;
183
		case 'V':
184
			fatal("the -V option is obsolete "
185
			    "and should not be used");
186
		case 'w':
187
			strlcat(diffargs, " -w", sizeof(diffargs));
188
			dflags |= D_IGNOREBLANKS;
189
			break;
190
		default:
191
			fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
192
			    cvs_cmd_diff.cmd_synopsis :
193
			    cvs_cmd_rdiff.cmd_synopsis);
194
		}
195
	}
196
197
2
	argc -= optind;
198
2
	argv += optind;
199
200
2
	cr.enterdir = NULL;
201
2
	cr.leavedir = NULL;
202
203
2
	if (cvs_cmdop == CVS_OP_RDIFF) {
204
		if (rev1 == NULL && rev2 == NULL && dateflag1 == NULL &&
205
		    dateflag2 == NULL)
206
			fatal("must specify at least one revision/date!");
207
208
		if (!argc)
209
			fatal("%s", cvs_cmd_rdiff.cmd_synopsis);
210
211
		if (!diff_format) {
212
			strlcat(diffargs, " -c", sizeof(diffargs));
213
			diff_format = D_CONTEXT;
214
		}
215
216
		flags |= CR_REPO;
217
	}
218
219
2
	if (cvsroot_is_remote()) {
220
		cvs_client_connect_to_server();
221
		cr.fileproc = cvs_client_sendfile;
222
223
		if (!(flags & CR_RECURSE_DIRS))
224
			cvs_client_send_request("Argument -l");
225
226
		if (kflag)
227
			cvs_client_send_request("Argument -k%s", koptstr);
228
229
		switch (diff_format) {
230
		case D_CONTEXT:
231
			if (cvs_cmdop == CVS_OP_RDIFF)
232
				cvs_client_send_request("Argument -c");
233
			else {
234
				cvs_client_send_request("Argument -C %d",
235
				    diff_context);
236
			}
237
			break;
238
		case D_RCSDIFF:
239
			cvs_client_send_request("Argument -n");
240
			break;
241
		case D_UNIFIED:
242
			if (cvs_cmdop == CVS_OP_RDIFF || diff_context == 3)
243
				cvs_client_send_request("Argument -u");
244
			else {
245
				cvs_client_send_request("Argument -U %d",
246
				    diff_context);
247
			}
248
			break;
249
		default:
250
			break;
251
		}
252
253
		if (Nflag == 1)
254
			cvs_client_send_request("Argument -N");
255
256
		if (dflags & D_PROTOTYPE)
257
			cvs_client_send_request("Argument -p");
258
259
		if (rev1 != NULL)
260
			cvs_client_send_request("Argument -r%s", rev1);
261
		if (rev2 != NULL)
262
			cvs_client_send_request("Argument -r%s", rev2);
263
264
		if (dateflag1 != NULL)
265
			cvs_client_send_request("Argument -D%s", dateflag1);
266
		if (dateflag2 != NULL)
267
			cvs_client_send_request("Argument -D%s", dateflag2);
268
	} else {
269

2
		if (cvs_cmdop == CVS_OP_RDIFF &&
270
		    chdir(current_cvsroot->cr_dir) == -1)
271
			fatal("cvs_diff: %s", strerror(errno));
272
273
2
		cr.fileproc = cvs_diff_local;
274
	}
275
276
2
	cr.flags = flags;
277
278
2
	diff_rev1 = diff_rev2 = NULL;
279
280

2
	if (cvs_cmdop == CVS_OP_DIFF || cvsroot_is_local()) {
281
2
		if (argc > 0)
282
1
			cvs_file_run(argc, argv, &cr);
283
		else
284
1
			cvs_file_run(1, &arg, &cr);
285
	}
286
287
2
	if (cvsroot_is_remote()) {
288
		cvs_client_send_files(argv, argc);
289
		cvs_client_senddir(".");
290
291
		cvs_client_send_request((cvs_cmdop == CVS_OP_RDIFF) ?
292
		    "rdiff" : "diff");
293
294
		cvs_client_get_responses();
295
	}
296
297
2
	return (0);
298
2
}
299
300
void
301
cvs_diff_local(struct cvs_file *cf)
302
{
303
	BUF *b1;
304
	int fd1, fd2;
305
12
	struct stat st;
306
6
	struct timeval tv[2], tv2[2];
307
6
	struct tm datetm;
308
6
	char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2;
309
310
	b1 = NULL;
311
	fd1 = fd2 = -1;
312
6
	p1 = p2 = NULL;
313
314
6
	cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path);
315
316
6
	if (cf->file_type == CVS_DIR) {
317
2
		if (verbosity > 1)
318
			cvs_log(LP_ERR, "Diffing inside %s", cf->file_path);
319
2
		return;
320
	}
321
322
4
	cvs_file_classify(cf, cvs_directory_tag);
323
324
4
	if (cvs_cmdop == CVS_OP_DIFF) {
325
4
		if (cf->file_ent == NULL) {
326
			cvs_log(LP_ERR, "I know nothing about %s",
327
			    cf->file_path);
328
			return;
329
		}
330
331
4
		switch (cf->file_ent->ce_status) {
332
		case CVS_ENT_ADDED:
333
			if (Nflag == 0) {
334
				cvs_log(LP_ERR, "%s is a new entry, no "
335
				    "comparison available", cf->file_path);
336
				return;
337
			}
338
			if (!(cf->file_flags & FILE_ON_DISK)) {
339
				cvs_log(LP_ERR, "cannot find %s",
340
				    cf->file_path);
341
				return;
342
			}
343
			break;
344
		case CVS_ENT_REMOVED:
345
			if (Nflag == 0) {
346
				cvs_log(LP_ERR, "%s was removed, no "
347
				    "comparison available", cf->file_path);
348
				return;
349
			}
350
			if (cf->file_rcs == NULL) {
351
				cvs_log(LP_ERR, "cannot find RCS file for %s",
352
				    cf->file_path);
353
				return;
354
			}
355
			break;
356
		default:
357
4
			if (!(cf->file_flags & FILE_ON_DISK)) {
358
				cvs_printf("? %s\n", cf->file_path);
359
				return;
360
			}
361
362
4
			if (cf->file_rcs == NULL) {
363
				cvs_log(LP_ERR, "cannot find RCS file for %s",
364
				    cf->file_path);
365
				return;
366
			}
367
			break;
368
		}
369
	}
370
371
12
	if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL &&
372
8
	    date1 == -1 && date2 == -1)
373
2
		return;
374
375

4
	if (cf->file_rcs != NULL && cf->file_rcs->rf_head == NULL) {
376
		cvs_log(LP_ERR, "no head revision in RCS file for %s\n",
377
		    cf->file_path);
378
		return;
379
	}
380
381

2
	if (kflag && cf->file_rcs != NULL)
382
		rcs_kwexp_set(cf->file_rcs, kflag);
383
384
2
	if (cf->file_rcs == NULL)
385
		diff_rev1 = NULL;
386
2
	else if (rev1 != NULL || date1 != -1) {
387
		cvs_specified_date = date1;
388
		diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs);
389
		if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) {
390
			if (rev1 != NULL) {
391
				cvs_log(LP_ERR, "tag %s not in file %s", rev1,
392
				    cf->file_path);
393
				goto cleanup;
394
			} else if (Nflag) {
395
				diff_rev1 = NULL;
396
			} else {
397
				gmtime_r(&cvs_specified_date, &datetm);
398
				strftime(tbuf, sizeof(tbuf),
399
				    "%Y.%m.%d.%H.%M.%S", &datetm);
400
				cvs_log(LP_ERR, "no revision for date %s in "
401
				    "file %s", tbuf, cf->file_path);
402
				goto cleanup;
403
			}
404
		} else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
405
		    force_head) {
406
			/* -f is not allowed for unknown symbols */
407
			if ((diff_rev1 = rcsnum_parse(rev1)) == NULL)
408
				fatal("no such tag %s", rev1);
409
			free(diff_rev1);
410
411
			diff_rev1 = cf->file_rcs->rf_head;
412
		}
413
		cvs_specified_date = -1;
414
2
	} else if (cvs_cmdop == CVS_OP_DIFF) {
415
2
		if (cf->file_ent->ce_status == CVS_ENT_ADDED)
416
			diff_rev1 = NULL;
417
		else
418
2
			diff_rev1 = cf->file_ent->ce_rev;
419
2
	}
420
421
2
	if (cf->file_rcs == NULL)
422
		diff_rev2 = NULL;
423
2
	else if (rev2 != NULL || date2 != -1) {
424
		cvs_specified_date = date2;
425
		diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs);
426
		if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) {
427
			if (rev2 != NULL) {
428
				cvs_log(LP_ERR, "tag %s not in file %s", rev2,
429
				    cf->file_path);
430
				goto cleanup;
431
			} else if (Nflag) {
432
				diff_rev2 = NULL;
433
			} else {
434
				gmtime_r(&cvs_specified_date, &datetm);
435
				strftime(tbuf, sizeof(tbuf),
436
				    "%Y.%m.%d.%H.%M.%S", &datetm);
437
				cvs_log(LP_ERR, "no revision for date %s in "
438
				    "file %s", tbuf, cf->file_path);
439
				goto cleanup;
440
			}
441
		} else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
442
		    force_head) {
443
			/* -f is not allowed for unknown symbols */
444
			if ((diff_rev2 = rcsnum_parse(rev2)) == NULL)
445
				fatal("no such tag %s", rev2);
446
			free(diff_rev2);
447
448
			diff_rev2 = cf->file_rcs->rf_head;
449
		}
450
		cvs_specified_date = -1;
451
2
	} else if (cvs_cmdop == CVS_OP_RDIFF)
452
		diff_rev2 = cf->file_rcs->rf_head;
453
2
	else if (cf->file_ent->ce_status == CVS_ENT_REMOVED)
454
		diff_rev2 = NULL;
455
456

2
	if (diff_rev1 != NULL && diff_rev2 != NULL &&
457
	    rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0)
458
		goto cleanup;
459
460
4
	switch (cvs_cmdop) {
461
	case CVS_OP_DIFF:
462
4
		if (cf->file_status == FILE_UPTODATE) {
463
2
			if (diff_rev2 == NULL &&
464
			    !rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0))
465
				goto cleanup;
466
		}
467
		break;
468
	case CVS_OP_RDIFF:
469
		if (diff_rev1 == NULL && diff_rev2 == NULL)
470
			goto cleanup;
471
		break;
472
	}
473
474
2
	cvs_printf("Index: %s\n", cf->file_path);
475
2
	if (cvs_cmdop == CVS_OP_DIFF)
476
2
		cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV,
477
2
		    cf->file_rcs != NULL ? cf->file_rpath : cf->file_path);
478
479
2
	if (diff_rev1 != NULL) {
480
2
		if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) {
481
2
			(void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
482
2
			cvs_printf("retrieving revision %s\n", rbuf);
483
2
		}
484
485
2
		tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1);
486
2
		tv[0].tv_usec = 0;
487
2
		tv[1] = tv[0];
488
489
2
		(void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
490
2
		fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0);
491
2
		if (futimes(fd1, tv) == -1)
492
			fatal("cvs_diff_local: utimes failed");
493
	}
494
495
2
	if (diff_rev2 != NULL) {
496
		if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) {
497
			(void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf));
498
			cvs_printf("retrieving revision %s\n", rbuf);
499
		}
500
501
		tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2);
502
		tv2[0].tv_usec = 0;
503
		tv2[1] = tv2[0];
504
505
		(void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
506
		fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0);
507
		if (futimes(fd2, tv2) == -1)
508
			fatal("cvs_diff_local: utimes failed");
509

4
	} else if (cvs_cmdop == CVS_OP_DIFF &&
510
2
	    (cf->file_flags & FILE_ON_DISK) &&
511
2
	    cf->file_ent->ce_status != CVS_ENT_REMOVED) {
512
2
		(void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
513

2
		if (cvs_server_active == 1 && cf->fd == -1) {
514
			tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs,
515
			    cf->file_ent->ce_rev);
516
			tv2[0].tv_usec = 0;
517
			tv2[1] = tv2[0];
518
519
			fd2 = rcs_rev_write_stmp(cf->file_rcs,
520
			    cf->file_ent->ce_rev, p2, 0);
521
			if (futimes(fd2, tv2) == -1)
522
				fatal("cvs_diff_local: futimes failed");
523
		} else {
524
2
			if (fstat(cf->fd, &st) == -1)
525
				fatal("fstat failed %s", strerror(errno));
526
2
			b1 = buf_load_fd(cf->fd);
527
528
2
			tv2[0].tv_sec = st.st_mtime;
529
2
			tv2[0].tv_usec = 0;
530
2
			tv2[1] = tv2[0];
531
532
2
			fd2 = buf_write_stmp(b1, p2, tv2);
533
2
			buf_free(b1);
534
		}
535
	}
536
537
4
	switch (cvs_cmdop) {
538
	case CVS_OP_DIFF:
539
2
		cvs_printf("%s", diffargs);
540
541
2
		if (rev1 != NULL && diff_rev1 != NULL) {
542
			(void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
543
			cvs_printf(" -r%s", rbuf);
544
545
			if (rev2 != NULL && diff_rev2 != NULL) {
546
				(void)rcsnum_tostr(diff_rev2, rbuf,
547
				    sizeof(rbuf));
548
				cvs_printf(" -r%s", rbuf);
549
			}
550
		}
551
552
2
		if (diff_rev2 == NULL)
553
2
			cvs_printf(" %s", cf->file_path);
554
2
		cvs_printf("\n");
555
2
		break;
556
	case CVS_OP_RDIFF:
557
		cvs_printf("diff ");
558
		switch (diff_format) {
559
		case D_CONTEXT:
560
			cvs_printf("-c ");
561
			break;
562
		case D_RCSDIFF:
563
			cvs_printf("-n ");
564
			break;
565
		case D_UNIFIED:
566
			cvs_printf("-u ");
567
			break;
568
		default:
569
			break;
570
		}
571
		if (diff_rev1 == NULL) {
572
			cvs_printf("%s ", CVS_PATH_DEVNULL);
573
		} else {
574
			(void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
575
			cvs_printf("%s:%s ", cf->file_path, rbuf);
576
		}
577
578
		if (diff_rev2 == NULL) {
579
			cvs_printf("%s:removed\n", cf->file_path);
580
		} else {
581
			(void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 :
582
			    cf->file_rcs->rf_head, rbuf, sizeof(rbuf));
583
			cvs_printf("%s:%s\n", cf->file_path, rbuf);
584
		}
585
		break;
586
	}
587
588
2
	if (fd1 == -1) {
589
		if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
590
			fatal("cannot open %s", CVS_PATH_DEVNULL);
591
	}
592
2
	if (fd2 == -1) {
593
		if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
594
			fatal("cannot open %s", CVS_PATH_DEVNULL);
595
	}
596
597

10
	if (diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL,
598
6
	    p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL,
599
4
	    dflags) == D_ERROR)
600
		fatal("cvs_diff_local: failed to get RCS patch");
601
602
2
	close(fd1);
603
2
	close(fd2);
604
605
2
	worklist_run(&temp_files, worklist_unlink);
606
607
2
	free(p1);
608
2
	free(p2);
609
610
cleanup:
611

4
	if (diff_rev1 != NULL &&
612

4
	    (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) &&
613
4
	    (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev))
614
		free(diff_rev1);
615
2
	diff_rev1 = NULL;
616
617

2
	if (diff_rev2 != NULL &&
618
	    (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head))
619
		free(diff_rev2);
620
2
	diff_rev2 = NULL;
621
8
}