GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/update.c Lines: 139 388 35.8 %
Date: 2017-11-07 Branches: 98 294 33.3 %

Line Branch Exec Source
1
/*	$OpenBSD: update.c,v 1.176 2017/06/01 08:08:24 joris Exp $	*/
2
/*
3
 * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/stat.h>
19
20
#include <dirent.h>
21
#include <errno.h>
22
#include <fcntl.h>
23
#include <stdint.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <unistd.h>
27
28
#include "cvs.h"
29
#include "diff.h"
30
#include "remote.h"
31
32
int	prune_dirs = 0;
33
int	print_stdout = 0;
34
int	build_dirs = 0;
35
int	reset_option = 0;
36
int	reset_tag = 0;
37
int 	backup_local_changes = 0;
38
char *cvs_specified_tag = NULL;
39
char *cvs_join_rev1 = NULL;
40
char *cvs_join_rev2 = NULL;
41
42
static char *koptstr;
43
static char *dateflag = NULL;
44
static int Aflag = 0;
45
46
static void update_clear_conflict(struct cvs_file *);
47
static void update_join_file(struct cvs_file *);
48
49
extern CVSENTRIES *current_list;
50
51
struct cvs_cmd cvs_cmd_update = {
52
	CVS_OP_UPDATE, CVS_USE_WDIR, "update",
53
	{ "up", "upd" },
54
	"Bring work tree in sync with repository",
55
	"[-ACdflPpR] [-D date | -r rev] [-I ign] [-j rev] [-k mode] "
56
	"[-t id] ...",
57
	"ACD:dfI:j:k:lPpQqRr:t:u",
58
	NULL,
59
	cvs_update
60
};
61
62
int
63
cvs_update(int argc, char **argv)
64
{
65
	int ch;
66
10
	char *arg = ".";
67
	int flags;
68
5
	struct cvs_recursion cr;
69
70
	flags = CR_RECURSE_DIRS;
71
72
18
	while ((ch = getopt(argc, argv, cvs_cmd_update.cmd_opts)) != -1) {
73




16
		switch (ch) {
74
		case 'A':
75
4
			Aflag = 1;
76
4
			if (koptstr == NULL)
77
4
				reset_option = 1;
78
4
			if (cvs_specified_tag == NULL)
79
4
				reset_tag = 1;
80
			break;
81
		case 'C':
82
			backup_local_changes = 1;
83
			break;
84
		case 'D':
85
			dateflag = optarg;
86
			if ((cvs_specified_date = date_parse(dateflag)) == -1)
87
				fatal("invalid date: %s", dateflag);
88
			reset_tag = 0;
89
			break;
90
		case 'd':
91
			build_dirs = 1;
92
			break;
93
		case 'f':
94
			break;
95
		case 'I':
96
			break;
97
		case 'j':
98
			if (cvs_join_rev1 == NULL)
99
				cvs_join_rev1 = optarg;
100
			else if (cvs_join_rev2 == NULL)
101
				cvs_join_rev2 = optarg;
102
			else
103
				fatal("too many -j options");
104
			break;
105
		case 'k':
106
2
			reset_option = 0;
107
2
			koptstr = optarg;
108
2
			kflag = rcs_kflag_get(koptstr);
109

4
			if (RCS_KWEXP_INVAL(kflag)) {
110
				cvs_log(LP_ERR,
111
				    "invalid RCS keyword expansion mode");
112
				fatal("%s", cvs_cmd_update.cmd_synopsis);
113
			}
114
			break;
115
		case 'l':
116
			flags &= ~CR_RECURSE_DIRS;
117
			break;
118
		case 'P':
119
			prune_dirs = 1;
120
			break;
121
		case 'p':
122
			print_stdout = 1;
123
			cvs_noexec = 1;
124
			break;
125
		case 'Q':
126
		case 'q':
127
			break;
128
		case 'R':
129
			flags |= CR_RECURSE_DIRS;
130
			break;
131
		case 'r':
132
2
			reset_tag = 0;
133
2
			cvs_specified_tag = optarg;
134
2
			break;
135
		case 'u':
136
			break;
137
		default:
138
			fatal("%s", cvs_cmd_update.cmd_synopsis);
139
		}
140
	}
141
142
5
	argc -= optind;
143
5
	argv += optind;
144
145
5
	if (cvsroot_is_local()) {
146
5
		cr.enterdir = cvs_update_enterdir;
147
5
		cr.leavedir = prune_dirs ? cvs_update_leavedir : NULL;
148
5
		cr.fileproc = cvs_update_local;
149
5
		flags |= CR_REPO;
150
5
	} else {
151
		cvs_client_connect_to_server();
152
		if (Aflag)
153
			cvs_client_send_request("Argument -A");
154
		if (dateflag != NULL)
155
			cvs_client_send_request("Argument -D%s", dateflag);
156
		if (build_dirs)
157
			cvs_client_send_request("Argument -d");
158
		if (kflag)
159
			cvs_client_send_request("Argument -k%s", koptstr);
160
		if (!(flags & CR_RECURSE_DIRS))
161
			cvs_client_send_request("Argument -l");
162
		if (prune_dirs)
163
			cvs_client_send_request("Argument -P");
164
		if (print_stdout)
165
			cvs_client_send_request("Argument -p");
166
167
		if (cvs_specified_tag != NULL)
168
			cvs_client_send_request("Argument -r%s",
169
			    cvs_specified_tag);
170
171
		cr.enterdir = NULL;
172
		cr.leavedir = NULL;
173
		cr.fileproc = cvs_client_sendfile;
174
	}
175
176
5
	cr.flags = flags;
177
178
5
	if (argc > 0)
179
		cvs_file_run(argc, argv, &cr);
180
	else
181
5
		cvs_file_run(1, &arg, &cr);
182
183
5
	if (cvsroot_is_remote()) {
184
		cvs_client_send_files(argv, argc);
185
		cvs_client_senddir(".");
186
		cvs_client_send_request("update");
187
		cvs_client_get_responses();
188
	}
189
190
5
	return (0);
191
5
}
192
193
void
194
cvs_update_enterdir(struct cvs_file *cf)
195
{
196
	CVSENTRIES *entlist;
197
32
	char *dirtag, *entry, fpath[PATH_MAX];
198
199
16
	cvs_log(LP_TRACE, "cvs_update_enterdir(%s)", cf->file_path);
200
201
16
	cvs_file_classify(cf, NULL);
202
203
16
	if (cf->file_status == DIR_CREATE && build_dirs == 1) {
204
6
		cvs_parse_tagfile(cf->file_wd, &dirtag, NULL, NULL);
205
12
		cvs_mkpath(cf->file_path, cvs_specified_tag != NULL ?
206
6
		    cvs_specified_tag : dirtag);
207
6
		free(dirtag);
208
209
6
		if ((cf->fd = open(cf->file_path, O_RDONLY)) == -1)
210
			fatal("cvs_update_enterdir: `%s': %s",
211
			    cf->file_path, strerror(errno));
212
213
6
		if (cvs_server_active == 1 && cvs_cmdop != CVS_OP_CHECKOUT)
214
			cvs_server_clear_sticky(cf->file_path);
215
216
6
		if (cvs_cmdop != CVS_OP_EXPORT) {
217
5
			(void)xasprintf(&entry, "D/%s////", cf->file_name);
218
219
5
			entlist = cvs_ent_open(cf->file_wd);
220
5
			cvs_ent_add(entlist, entry);
221
5
			free(entry);
222
5
		}
223

20
	} else if ((cf->file_status == DIR_CREATE && build_dirs == 0) ||
224
10
		    cf->file_status == FILE_UNKNOWN) {
225
		cf->file_status = FILE_SKIP;
226
10
	} else if (reset_tag) {
227
8
		(void)xsnprintf(fpath, PATH_MAX, "%s/%s",
228
4
		    cf->file_path, CVS_PATH_TAG);
229
4
		(void)unlink(fpath);
230
4
	} else {
231
6
		if (cvs_specified_tag != NULL || cvs_specified_date != -1)
232
4
			cvs_write_tagfile(cf->file_path,
233
				    cvs_specified_tag, NULL);
234
	}
235
16
}
236
237
void
238
cvs_update_leavedir(struct cvs_file *cf)
239
{
240
	int nbytes;
241
	int isempty;
242
	size_t bufsize;
243
2
	struct stat st;
244
	struct dirent *dp;
245
	char *buf, *ebuf, *cp;
246
	CVSENTRIES *entlist;
247
248
1
	cvs_log(LP_TRACE, "cvs_update_leavedir(%s)", cf->file_path);
249
250

1
	if (cvs_server_active == 1 && !strcmp(cf->file_name, "."))
251
		return;
252
253
1
	entlist = cvs_ent_open(cf->file_path);
254
1
	if (!TAILQ_EMPTY(&(entlist->cef_ent))) {
255
		isempty = 0;
256
		goto prune_it;
257
	}
258
259
1
	if (fstat(cf->fd, &st) == -1)
260
		fatal("cvs_update_leavedir: %s", strerror(errno));
261
262
1
	if ((uintmax_t)st.st_size > SIZE_MAX)
263
		fatal("cvs_update_leavedir: %s: file size too big",
264
		    cf->file_name);
265
266
1
	bufsize = (st.st_size > st.st_blksize) ? st.st_size : st.st_blksize;
267
268
	isempty = 1;
269
1
	buf = xmalloc(bufsize);
270
271
1
	if (lseek(cf->fd, 0, SEEK_SET) == -1)
272
		fatal("cvs_update_leavedir: %s", strerror(errno));
273
274
2
	while ((nbytes = getdents(cf->fd, buf, bufsize)) > 0) {
275
1
		ebuf = buf + nbytes;
276
		cp = buf;
277
278
4
		while (cp < ebuf) {
279
3
			dp = (struct dirent *)cp;
280

4
			if (!strcmp(dp->d_name, ".") ||
281
2
			    !strcmp(dp->d_name, "..") ||
282
1
			    dp->d_fileno == 0) {
283
2
				cp += dp->d_reclen;
284
2
				continue;
285
			}
286
287
1
			if (strcmp(dp->d_name, CVS_PATH_CVSDIR))
288
1
				isempty = 0;
289
290
1
			if (isempty == 0)
291
				break;
292
293
			cp += dp->d_reclen;
294
		}
295
	}
296
297
1
	if (nbytes == -1)
298
		fatal("cvs_update_leavedir: %s", strerror(errno));
299
300
1
	free(buf);
301
302
prune_it:
303
1
	if ((isempty == 1 && prune_dirs == 1) ||
304
1
	    (cvs_server_active == 1 && cvs_cmdop == CVS_OP_CHECKOUT)) {
305
		/* XXX */
306
		cvs_rmdir(cf->file_path);
307
308
		if (cvs_server_active == 0 && cvs_cmdop != CVS_OP_EXPORT) {
309
			entlist = cvs_ent_open(cf->file_wd);
310
			cvs_ent_remove(entlist, cf->file_name);
311
		}
312
	}
313
2
}
314
315
void
316
cvs_update_local(struct cvs_file *cf)
317
{
318
	CVSENTRIES *entlist;
319
	int ent_kflag, rcs_kflag, ret, flags;
320
114
	char *tag, rbuf[CVS_REV_BUFSZ];
321
322
57
	cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path);
323
324
57
	if (cf->file_type == CVS_DIR) {
325
16
		if (cf->file_status == FILE_SKIP) {
326
			if (cvs_cmdop == CVS_OP_EXPORT && verbosity > 0)
327
				cvs_printf("? %s\n", cf->file_path);
328
			return;
329
		}
330
331
32
		if (cf->file_status != FILE_UNKNOWN &&
332
16
		    verbosity > 1)
333
			cvs_log(LP_ERR, "Updating %s", cf->file_path);
334
16
		return;
335
	}
336
337
	flags = 0;
338
41
	if (cvs_specified_tag != NULL)
339
19
		tag = cvs_specified_tag;
340
	else
341
22
		tag = cvs_directory_tag;
342
343
41
	cvs_file_classify(cf, tag);
344
345

51
	if (kflag && cf->file_rcs != NULL)
346
10
		rcs_kwexp_set(cf->file_rcs, kflag);
347
348
41
	if ((cf->file_status == FILE_UPTODATE ||
349

41
	    cf->file_status == FILE_MODIFIED) && cf->file_ent != NULL &&
350
14
	    cf->file_ent->ce_tag != NULL && reset_tag) {
351
6
		if (cf->file_status == FILE_MODIFIED)
352
			cf->file_status = FILE_MERGE;
353
		else
354
			cf->file_status = FILE_CHECKOUT;
355
356
6
		if ((cf->file_rcsrev = rcs_head_get(cf->file_rcs)) == NULL)
357
			fatal("no head revision in RCS file for %s",
358
			    cf->file_path);
359
360
		/* might be a bit overkill */
361
6
		if (cvs_server_active == 1)
362
			cvs_server_clear_sticky(cf->file_wd);
363
	}
364
365
41
	if (print_stdout) {
366

3
		if (cf->file_status != FILE_UNKNOWN && cf->file_rcs != NULL &&
367

2
		    cf->file_rcsrev != NULL && !cf->file_rcs->rf_dead &&
368
1
		    (cf->file_flags & FILE_HAS_TAG)) {
369
1
			rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf));
370
1
			if (verbosity > 1) {
371
				cvs_log(LP_RCS, RCS_DIFF_DIV);
372
				cvs_log(LP_RCS, "Checking out %s",
373
				    cf->file_path);
374
				cvs_log(LP_RCS, "RCS:  %s", cf->file_rpath);
375
				cvs_log(LP_RCS, "VERS: %s", rbuf);
376
				cvs_log(LP_RCS, "***************");
377
			}
378
1
			cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_DUMP);
379
1
		}
380
1
		return;
381
	}
382
383
40
	if (cf->file_ent != NULL) {
384
15
		if (cf->file_ent->ce_opts == NULL) {
385
6
			if (kflag)
386
				cf->file_status = FILE_CHECKOUT;
387
9
		} else if (cf->file_rcs != NULL) {
388
9
			if (strlen(cf->file_ent->ce_opts) < 3)
389
				fatal("malformed option for file %s",
390
				    cf->file_path);
391
392
9
			ent_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2);
393
9
			rcs_kflag = rcs_kwexp_get(cf->file_rcs);
394
395

18
			if ((kflag && (kflag != ent_kflag)) ||
396
6
			    (reset_option && (ent_kflag != rcs_kflag)))
397
9
				cf->file_status = FILE_CHECKOUT;
398
		}
399
	}
400
401



80
	switch (cf->file_status) {
402
	case FILE_UNKNOWN:
403
		cvs_printf("? %s\n", cf->file_path);
404
		break;
405
	case FILE_MODIFIED:
406
		if (backup_local_changes) {
407
			cvs_backup_file(cf);
408
409
			cvs_checkout_file(cf, cf->file_rcsrev, NULL, flags);
410
			cvs_printf("U %s\n", cf->file_path);
411
		} else {
412
			ret = update_has_conflict_markers(cf);
413
			if (cf->file_ent->ce_conflict != NULL && ret == 1)
414
				cvs_printf("C %s\n", cf->file_path);
415
			else {
416
				if (cf->file_ent->ce_conflict != NULL && ret == 0)
417
					update_clear_conflict(cf);
418
				cvs_printf("M %s\n", cf->file_path);
419
			}
420
		}
421
		break;
422
	case FILE_ADDED:
423
		cvs_printf("A %s\n", cf->file_path);
424
		break;
425
	case FILE_REMOVED:
426
		cvs_printf("R %s\n", cf->file_path);
427
		break;
428
	case FILE_CONFLICT:
429
		cvs_printf("C %s\n", cf->file_path);
430
		break;
431
	case FILE_LOST:
432
	case FILE_CHECKOUT:
433
	case FILE_PATCH:
434

93
		if (!reset_tag && (tag != NULL || cvs_specified_date != -1 ||
435
41
		    cvs_directory_date != -1 || (cf->file_ent != NULL &&
436
		    cf->file_ent->ce_tag != NULL)))
437
17
			flags = CO_SETSTICKY;
438
439

60
		if (cf->file_flags & FILE_ON_DISK && (cf->file_ent == NULL ||
440
12
		    cf->file_ent->ce_type == CVS_ENT_NONE)) {
441
1
			cvs_log(LP_ERR, "move away %s; it is in the way",
442
1
			    cf->file_path);
443
1
			cvs_printf("C %s\n", cf->file_path);
444
1
		} else {
445
34
			cvs_checkout_file(cf, cf->file_rcsrev, tag, flags);
446
34
			cvs_printf("U %s\n", cf->file_path);
447
34
			cvs_history_add(CVS_HISTORY_UPDATE_CO, cf, NULL);
448
		}
449
		break;
450
	case FILE_MERGE:
451
		d3rev1 = cf->file_ent->ce_rev;
452
		d3rev2 = cf->file_rcsrev;
453
		cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_MERGE);
454
455
		if (diff3_conflicts != 0) {
456
			cvs_printf("C %s\n", cf->file_path);
457
			cvs_history_add(CVS_HISTORY_UPDATE_MERGED_ERR,
458
			    cf, NULL);
459
		} else {
460
			update_clear_conflict(cf);
461
			cvs_printf("M %s\n", cf->file_path);
462
			cvs_history_add(CVS_HISTORY_UPDATE_MERGED, cf, NULL);
463
		}
464
		break;
465
	case FILE_UNLINK:
466
		(void)unlink(cf->file_path);
467
	case FILE_REMOVE_ENTRY:
468
		entlist = cvs_ent_open(cf->file_wd);
469
		cvs_ent_remove(entlist, cf->file_name);
470
		cvs_history_add(CVS_HISTORY_UPDATE_REMOVE, cf, NULL);
471
472
		if (cvs_server_active == 1)
473
			cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_REMOVE);
474
		break;
475
	case FILE_UPTODATE:
476
5
		if (cvs_cmdop != CVS_OP_UPDATE)
477
			break;
478
479
9
		if (reset_tag != 1 && reset_option != 1 &&
480
6
		    cvs_specified_tag == NULL && cvs_specified_date == -1)
481
			break;
482
483
		if (cf->file_rcs->rf_dead != 1 &&
484
		    (cf->file_flags & FILE_HAS_TAG))
485
			cvs_checkout_file(cf, cf->file_rcsrev,
486
			    tag, CO_SETSTICKY);
487
		break;
488
	default:
489
		break;
490
	}
491
492
40
	if (cvs_join_rev1 != NULL)
493
		update_join_file(cf);
494
97
}
495
496
static void
497
update_clear_conflict(struct cvs_file *cf)
498
{
499
	CVSENTRIES *entlist;
500
	char *entry, revbuf[CVS_REV_BUFSZ];
501
	char sticky[CVS_ENT_MAXLINELEN], opt[4];
502
503
	cvs_log(LP_TRACE, "update_clear_conflict(%s)", cf->file_path);
504
505
	rcsnum_tostr(cf->file_rcsrev, revbuf, sizeof(revbuf));
506
507
	sticky[0] = '\0';
508
	if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL)
509
		(void)xsnprintf(sticky, sizeof(sticky), "T%s",
510
		    cf->file_ent->ce_tag);
511
512
	opt[0] = '\0';
513
	if (cf->file_ent != NULL && cf->file_ent->ce_opts != NULL)
514
		strlcpy(opt, cf->file_ent->ce_opts, sizeof(opt));
515
516
	entry = xmalloc(CVS_ENT_MAXLINELEN);
517
	cvs_ent_line_str(cf->file_name, revbuf, "Result of merge",
518
	    opt[0] != '\0' ? opt : "", sticky, 0, 0,
519
	    entry, CVS_ENT_MAXLINELEN);
520
521
	entlist = cvs_ent_open(cf->file_wd);
522
	cvs_ent_add(entlist, entry);
523
	free(entry);
524
}
525
526
/*
527
 * XXX - this is the way GNU cvs checks for outstanding conflicts
528
 * in a file after a merge. It is a very very bad approach and
529
 * should be looked at once opencvs is working decently.
530
 */
531
int
532
update_has_conflict_markers(struct cvs_file *cf)
533
{
534
	BUF *bp;
535
	int conflict;
536
	char *content;
537
	struct rcs_line *lp;
538
	struct rcs_lines *lines;
539
	size_t len;
540
541
	cvs_log(LP_TRACE, "update_has_conflict_markers(%s)", cf->file_path);
542
543
	if (!(cf->file_flags & FILE_ON_DISK) || cf->file_ent == NULL)
544
		return (0);
545
546
	bp = buf_load_fd(cf->fd);
547
548
	buf_putc(bp, '\0');
549
	len = buf_len(bp);
550
	content = buf_release(bp);
551
	if ((lines = cvs_splitlines(content, len)) == NULL)
552
		fatal("update_has_conflict_markers: failed to split lines");
553
554
	conflict = 0;
555
	TAILQ_FOREACH(lp, &(lines->l_lines), l_list) {
556
		if (lp->l_line == NULL)
557
			continue;
558
559
		if (!strncmp(lp->l_line, RCS_CONFLICT_MARKER1,
560
		    sizeof(RCS_CONFLICT_MARKER1) - 1) ||
561
		    !strncmp(lp->l_line, RCS_CONFLICT_MARKER2,
562
		    sizeof(RCS_CONFLICT_MARKER2) - 1) ||
563
		    !strncmp(lp->l_line, RCS_CONFLICT_MARKER3,
564
		    sizeof(RCS_CONFLICT_MARKER3) - 1)) {
565
			conflict = 1;
566
			break;
567
		}
568
	}
569
570
	cvs_freelines(lines);
571
	free(content);
572
	return (conflict);
573
}
574
575
void
576
update_join_file(struct cvs_file *cf)
577
{
578
	time_t told;
579
	RCSNUM *rev1, *rev2;
580
	const char *state1, *state2;
581
	char rbuf[CVS_REV_BUFSZ], *jrev1, *jrev2, *p;
582
583
	rev1 = rev2 = NULL;
584
	jrev1 = jrev2 = NULL;
585
586
	jrev1 = xstrdup(cvs_join_rev1);
587
	if (cvs_join_rev2 != NULL)
588
		jrev2 = xstrdup(cvs_join_rev2);
589
590
	if (jrev2 == NULL) {
591
		jrev2 = jrev1;
592
		jrev1 = NULL;
593
	}
594
595
	told = cvs_specified_date;
596
597
	if ((p = strchr(jrev2, ':')) != NULL) {
598
		(*p++) = '\0';
599
		if ((cvs_specified_date = date_parse(p)) == -1) {
600
			cvs_printf("invalid date: %s", p);
601
			goto out;
602
		}
603
	}
604
605
	rev2 = rcs_translate_tag(jrev2, cf->file_rcs);
606
	cvs_specified_date = told;
607
608
	if (jrev1 != NULL) {
609
		if ((p = strchr(jrev1, ':')) != NULL) {
610
			(*p++) = '\0';
611
			if ((cvs_specified_date = date_parse(p)) == -1) {
612
				cvs_printf("invalid date: %s", p);
613
				goto out;
614
			}
615
		}
616
617
		rev1 = rcs_translate_tag(jrev1, cf->file_rcs);
618
		cvs_specified_date = told;
619
	} else {
620
		if (rev2 == NULL)
621
			goto out;
622
623
		rev1 = rcsnum_alloc();
624
		rcsnum_cpy(cf->file_rcsrev, rev1, 0);
625
	}
626
627
	state1 = state2 = RCS_STATE_DEAD;
628
629
	if (rev1 != NULL)
630
		state1 = rcs_state_get(cf->file_rcs, rev1);
631
	if (rev2 != NULL)
632
		state2 = rcs_state_get(cf->file_rcs, rev2);
633
634
	if (rev2 == NULL || !strcmp(state2, RCS_STATE_DEAD)) {
635
		if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD))
636
			goto out;
637
638
		if (cf->file_status == FILE_REMOVED ||
639
		    cf->file_rcs->rf_dead == 1)
640
			goto out;
641
642
		if (cf->file_status == FILE_MODIFIED ||
643
		    cf->file_status == FILE_ADDED)
644
			goto out;
645
646
		(void)unlink(cf->file_path);
647
		(void)close(cf->fd);
648
		cf->fd = -1;
649
		cvs_remove_local(cf);
650
		goto out;
651
	}
652
653
	if (cf->file_ent != NULL) {
654
		if (!rcsnum_cmp(cf->file_ent->ce_rev, rev2, 0))
655
			goto out;
656
	}
657
658
	if (cf->file_rcsrev == NULL) {
659
		cvs_printf("non-mergable file: %s has no head revision!\n",
660
		    cf->file_path);
661
		goto out;
662
	}
663
664
	if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) {
665
		if (cf->file_flags & FILE_ON_DISK) {
666
			cvs_printf("%s exists but has been added in %s\n",
667
			    cf->file_path, jrev2);
668
		} else {
669
			cvs_printf("A %s\n", cf->file_path);
670
			cvs_checkout_file(cf, cf->file_rcsrev, NULL, 0);
671
			cvs_add_local(cf);
672
		}
673
		goto out;
674
	}
675
676
	if (!rcsnum_cmp(rev1, rev2, 0))
677
		goto out;
678
679
	if (!(cf->file_flags & FILE_ON_DISK)) {
680
		cvs_printf("%s does not exist but is present in %s\n",
681
		    cf->file_path, jrev2);
682
		goto out;
683
	}
684
685
	if (rcs_kwexp_get(cf->file_rcs) & RCS_KWEXP_NONE) {
686
		cvs_printf("non-mergable file: %s needs merge!\n",
687
		    cf->file_path);
688
		goto out;
689
	}
690
691
	cvs_printf("joining ");
692
	rcsnum_tostr(rev1, rbuf, sizeof(rbuf));
693
	cvs_printf("%s ", rbuf);
694
695
	rcsnum_tostr(rev2, rbuf, sizeof(rbuf));
696
	cvs_printf("%s ", rbuf);
697
698
	rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf));
699
	cvs_printf("into %s (%s)\n", cf->file_path, rbuf);
700
701
	d3rev1 = rev1;
702
	d3rev2 = rev2;
703
	cvs_checkout_file(cf, cf->file_rcsrev, NULL, CO_MERGE);
704
705
	if (diff3_conflicts == 0)
706
		update_clear_conflict(cf);
707
708
out:
709
	free(rev1);
710
	free(rev2);
711
	free(jrev1);
712
	free(jrev2);
713
}
714
715
void
716
cvs_backup_file(struct cvs_file *cf)
717
{
718
	char	 backup_name[PATH_MAX];
719
	char	 revstr[RCSNUM_MAXSTR];
720
721
	if (cf->file_status == FILE_ADDED)
722
		(void)xsnprintf(revstr, sizeof(revstr), "0");
723
	else
724
		rcsnum_tostr(cf->file_ent->ce_rev, revstr, sizeof(revstr));
725
726
	(void)xsnprintf(backup_name, PATH_MAX, "%s/.#%s.%s",
727
	    cf->file_wd, cf->file_name, revstr);
728
729
	cvs_file_copy(cf->file_path, backup_name);
730
731
	(void)xsnprintf(backup_name, PATH_MAX, ".#%s.%s",
732
	    cf->file_name, revstr);
733
	cvs_printf("(Locally modified %s moved to %s)\n",
734
		   cf->file_name, backup_name);
735
}