xref: /openbsd-src/usr.bin/cvs/update.c (revision d874cce4b1d9fe6b41c9e4f2117a77d8a4a37b92)
1 /*	$OpenBSD: update.c,v 1.155 2008/06/19 19:04:59 tobias 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 <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include "cvs.h"
26 #include "diff.h"
27 #include "remote.h"
28 
29 int	prune_dirs = 0;
30 int	print_stdout = 0;
31 int	build_dirs = 0;
32 int	reset_option = 0;
33 int	reset_tag = 0;
34 char *cvs_specified_tag = NULL;
35 char *cvs_join_rev1 = NULL;
36 char *cvs_join_rev2 = NULL;
37 
38 static char *koptstr;
39 static char *dateflag = NULL;
40 static int Aflag = 0;
41 
42 static void update_clear_conflict(struct cvs_file *);
43 static void update_join_file(struct cvs_file *);
44 
45 extern CVSENTRIES *current_list;
46 
47 struct cvs_cmd cvs_cmd_update = {
48 	CVS_OP_UPDATE, CVS_USE_WDIR, "update",
49 	{ "up", "upd" },
50 	"Bring work tree in sync with repository",
51 	"[-ACdflPpR] [-D date | -r rev] [-I ign] [-j rev] [-k mode] "
52 	"[-t id] ...",
53 	"ACD:dfI:j:k:lPpQqRr:t:u",
54 	NULL,
55 	cvs_update
56 };
57 
58 int
59 cvs_update(int argc, char **argv)
60 {
61 	int ch;
62 	char *arg = ".";
63 	int flags;
64 	struct cvs_recursion cr;
65 
66 	flags = CR_RECURSE_DIRS;
67 
68 	while ((ch = getopt(argc, argv, cvs_cmd_update.cmd_opts)) != -1) {
69 		switch (ch) {
70 		case 'A':
71 			Aflag = 1;
72 			if (koptstr == NULL)
73 				reset_option = 1;
74 			if (cvs_specified_tag == NULL)
75 				reset_tag = 1;
76 			break;
77 		case 'C':
78 			break;
79 		case 'D':
80 			dateflag = optarg;
81 			cvs_specified_date = cvs_date_parse(dateflag);
82 			reset_tag = 0;
83 			break;
84 		case 'd':
85 			build_dirs = 1;
86 			break;
87 		case 'f':
88 			break;
89 		case 'I':
90 			break;
91 		case 'j':
92 			if (cvs_join_rev1 == NULL)
93 				cvs_join_rev1 = optarg;
94 			else if (cvs_join_rev2 == NULL)
95 				cvs_join_rev2 = optarg;
96 			else
97 				fatal("too many -j options");
98 			break;
99 		case 'k':
100 			reset_option = 0;
101 			koptstr = optarg;
102 			kflag = rcs_kflag_get(koptstr);
103 			if (RCS_KWEXP_INVAL(kflag)) {
104 				cvs_log(LP_ERR,
105 				    "invalid RCS keyword expansion mode");
106 				fatal("%s", cvs_cmd_update.cmd_synopsis);
107 			}
108 			break;
109 		case 'l':
110 			flags &= ~CR_RECURSE_DIRS;
111 			break;
112 		case 'P':
113 			prune_dirs = 1;
114 			break;
115 		case 'p':
116 			print_stdout = 1;
117 			cvs_noexec = 1;
118 			break;
119 		case 'Q':
120 		case 'q':
121 			break;
122 		case 'R':
123 			flags |= CR_RECURSE_DIRS;
124 			break;
125 		case 'r':
126 			reset_tag = 0;
127 			cvs_specified_tag = optarg;
128 			break;
129 		case 'u':
130 			break;
131 		default:
132 			fatal("%s", cvs_cmd_update.cmd_synopsis);
133 		}
134 	}
135 
136 	argc -= optind;
137 	argv += optind;
138 
139 	if (current_cvsroot->cr_method == CVS_METHOD_LOCAL) {
140 		cr.enterdir = cvs_update_enterdir;
141 		cr.leavedir = prune_dirs ? cvs_update_leavedir : NULL;
142 		cr.fileproc = cvs_update_local;
143 		flags |= CR_REPO;
144 	} else {
145 		cvs_client_connect_to_server();
146 		if (Aflag)
147 			cvs_client_send_request("Argument -A");
148 		if (dateflag != NULL)
149 			cvs_client_send_request("Argument -D%s", dateflag);
150 		if (build_dirs)
151 			cvs_client_send_request("Argument -d");
152 		if (kflag)
153 			cvs_client_send_request("Argument -k%s", koptstr);
154 		if (!(flags & CR_RECURSE_DIRS))
155 			cvs_client_send_request("Argument -l");
156 		if (prune_dirs)
157 			cvs_client_send_request("Argument -P");
158 		if (print_stdout)
159 			cvs_client_send_request("Argument -p");
160 
161 		if (cvs_specified_tag != NULL)
162 			cvs_client_send_request("Argument -r%s",
163 			    cvs_specified_tag);
164 
165 		cr.enterdir = NULL;
166 		cr.leavedir = NULL;
167 		cr.fileproc = cvs_client_sendfile;
168 	}
169 
170 	cr.flags = flags;
171 
172 	if (argc > 0)
173 		cvs_file_run(argc, argv, &cr);
174 	else
175 		cvs_file_run(1, &arg, &cr);
176 
177 	if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
178 		cvs_client_send_files(argv, argc);
179 		cvs_client_senddir(".");
180 		cvs_client_send_request("update");
181 		cvs_client_get_responses();
182 	}
183 
184 	return (0);
185 }
186 
187 void
188 cvs_update_enterdir(struct cvs_file *cf)
189 {
190 	CVSENTRIES *entlist;
191 	char *dirtag, *entry, fpath[MAXPATHLEN];
192 
193 	cvs_log(LP_TRACE, "cvs_update_enterdir(%s)", cf->file_path);
194 
195 	cvs_file_classify(cf, NULL);
196 
197 	if (cf->file_status == DIR_CREATE && build_dirs == 1) {
198 		cvs_parse_tagfile(cf->file_wd, &dirtag, NULL, NULL);
199 		cvs_mkpath(cf->file_path, cvs_specified_tag != NULL ?
200 		    cvs_specified_tag : dirtag);
201 		if (dirtag != NULL)
202 			xfree(dirtag);
203 
204 		if ((cf->fd = open(cf->file_path, O_RDONLY)) == -1)
205 			fatal("cvs_update_enterdir: `%s': %s",
206 			    cf->file_path, strerror(errno));
207 
208 		if (cvs_server_active == 1 && cvs_cmdop != CVS_OP_CHECKOUT)
209 			cvs_server_clear_sticky(cf->file_path);
210 
211 		if (cvs_cmdop != CVS_OP_EXPORT) {
212 			(void)xasprintf(&entry, "D/%s////", cf->file_name);
213 
214 			entlist = cvs_ent_open(cf->file_wd);
215 			cvs_ent_add(entlist, entry);
216 			xfree(entry);
217 		}
218 	} else if ((cf->file_status == DIR_CREATE && build_dirs == 0) ||
219 		    cf->file_status == FILE_UNKNOWN) {
220 		cf->file_status = FILE_SKIP;
221 	} else if (reset_tag) {
222 		(void)xsnprintf(fpath, MAXPATHLEN, "%s/%s",
223 		    cf->file_path, CVS_PATH_TAG);
224 		(void)unlink(fpath);
225 	} else {
226 		if (cvs_specified_tag != NULL || cvs_specified_date != -1)
227 			cvs_write_tagfile(cf->file_path,
228 				    cvs_specified_tag, NULL);
229 	}
230 }
231 
232 void
233 cvs_update_leavedir(struct cvs_file *cf)
234 {
235 	long base;
236 	int nbytes;
237 	int isempty;
238 	size_t bufsize;
239 	struct stat st;
240 	struct dirent *dp;
241 	char *buf, *ebuf, *cp;
242 	CVSENTRIES *entlist;
243 
244 	cvs_log(LP_TRACE, "cvs_update_leavedir(%s)", cf->file_path);
245 
246 	if (cvs_server_active == 1 && !strcmp(cf->file_name, "."))
247 		return;
248 
249 	if (fstat(cf->fd, &st) == -1)
250 		fatal("cvs_update_leavedir: %s", strerror(errno));
251 
252 	bufsize = st.st_size;
253 	if (bufsize < st.st_blksize)
254 		bufsize = st.st_blksize;
255 
256 	if (st.st_size > SIZE_MAX)
257 		fatal("cvs_update_leavedir: %s: file size too big",
258 		    cf->file_name);
259 
260 	isempty = 1;
261 	buf = xmalloc(bufsize);
262 
263 	if (lseek(cf->fd, 0, SEEK_SET) == -1)
264 		fatal("cvs_update_leavedir: %s", strerror(errno));
265 
266 	while ((nbytes = getdirentries(cf->fd, buf, bufsize, &base)) > 0) {
267 		ebuf = buf + nbytes;
268 		cp = buf;
269 
270 		while (cp < ebuf) {
271 			dp = (struct dirent *)cp;
272 			if (!strcmp(dp->d_name, ".") ||
273 			    !strcmp(dp->d_name, "..") ||
274 			    dp->d_fileno == 0) {
275 				cp += dp->d_reclen;
276 				continue;
277 			}
278 
279 			if (!strcmp(dp->d_name, CVS_PATH_CVSDIR)) {
280 				entlist = cvs_ent_open(cf->file_path);
281 				if (!TAILQ_EMPTY(&(entlist->cef_ent)))
282 					isempty = 0;
283 			} else {
284 				isempty = 0;
285 			}
286 
287 			if (isempty == 0)
288 				break;
289 
290 			cp += dp->d_reclen;
291 		}
292 	}
293 
294 	if (nbytes == -1)
295 		fatal("cvs_update_leavedir: %s", strerror(errno));
296 
297 	xfree(buf);
298 
299 	if ((isempty == 1 && prune_dirs == 1) ||
300 	    (cvs_server_active == 1 && cvs_cmdop == CVS_OP_CHECKOUT)) {
301 		/* XXX */
302 		cvs_rmdir(cf->file_path);
303 
304 		if (cvs_server_active == 0 && cvs_cmdop != CVS_OP_EXPORT) {
305 			entlist = cvs_ent_open(cf->file_wd);
306 			cvs_ent_remove(entlist, cf->file_name);
307 		}
308 	}
309 }
310 
311 void
312 cvs_update_local(struct cvs_file *cf)
313 {
314 	CVSENTRIES *entlist;
315 	int ent_kflag, rcs_kflag, ret, flags;
316 	char *tag, rbuf[CVS_REV_BUFSZ];
317 
318 	cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path);
319 
320 	if (cf->file_type == CVS_DIR) {
321 		if (cf->file_status == FILE_SKIP) {
322 			if (cvs_cmdop == CVS_OP_EXPORT && verbosity > 0)
323 				cvs_printf("? %s\n", cf->file_path);
324 			return;
325 		}
326 
327 		if (cf->file_status != FILE_UNKNOWN &&
328 		    verbosity > 1)
329 			cvs_log(LP_NOTICE, "Updating %s", cf->file_path);
330 		return;
331 	}
332 
333 	flags = 0;
334 	if (cvs_specified_tag != NULL)
335 		tag = cvs_specified_tag;
336 	else if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL)
337 		tag = cf->file_ent->ce_tag;
338 	else
339 		tag = cvs_directory_tag;
340 
341 	cvs_file_classify(cf, tag);
342 
343 	if (kflag && cf->file_rcs != NULL)
344 		rcs_kwexp_set(cf->file_rcs, kflag);
345 
346 	if ((cf->file_status == FILE_UPTODATE ||
347 	    cf->file_status == FILE_MODIFIED) && cf->file_ent != NULL &&
348 	    cf->file_ent->ce_tag != NULL && reset_tag) {
349 		if (cf->file_status == FILE_MODIFIED)
350 			cf->file_status = FILE_MERGE;
351 		else
352 			cf->file_status = FILE_CHECKOUT;
353 
354 		if ((cf->file_rcsrev = rcs_head_get(cf->file_rcs)) == NULL)
355 			fatal("no head revision in RCS file for %s",
356 			    cf->file_path);
357 
358 		/* might be a bit overkill */
359 		if (cvs_server_active == 1)
360 			cvs_server_clear_sticky(cf->file_wd);
361 	}
362 
363 	if (print_stdout) {
364 		if (cf->file_status != FILE_UNKNOWN && cf->file_rcs != NULL &&
365 		    cf->file_rcsrev != NULL && !cf->file_rcs->rf_dead &&
366 		    (cf->file_flags & FILE_HAS_TAG)) {
367 			rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf));
368 			if (verbosity > 1) {
369 				cvs_log(LP_RCS, RCS_DIFF_DIV);
370 				cvs_log(LP_RCS, "Checking out %s",
371 				    cf->file_path);
372 				cvs_log(LP_RCS, "RCS:  %s", cf->file_rpath);
373 				cvs_log(LP_RCS, "VERS: %s", rbuf);
374 				cvs_log(LP_RCS, "***************");
375 			}
376 			cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_DUMP);
377 		}
378 		return;
379 	}
380 
381 	if (cf->file_ent != NULL) {
382 		if (cf->file_ent->ce_opts == NULL) {
383 			if (kflag)
384 				cf->file_status = FILE_CHECKOUT;
385 		} else if (cf->file_rcs != NULL) {
386 			if (strlen(cf->file_ent->ce_opts) < 3)
387 				fatal("malformed option for file %s",
388 				    cf->file_path);
389 
390 			ent_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2);
391 			rcs_kflag = rcs_kwexp_get(cf->file_rcs);
392 
393 			if ((kflag && (kflag != ent_kflag)) ||
394 			    (reset_option && (ent_kflag != rcs_kflag)))
395 				cf->file_status = FILE_CHECKOUT;
396 		}
397 	}
398 
399 	switch (cf->file_status) {
400 	case FILE_UNKNOWN:
401 		cvs_printf("? %s\n", cf->file_path);
402 		break;
403 	case FILE_MODIFIED:
404 		ret = update_has_conflict_markers(cf);
405 		if (cf->file_ent->ce_conflict != NULL && ret == 1) {
406 			cvs_printf("C %s\n", cf->file_path);
407 		} else {
408 			if (cf->file_ent->ce_conflict != NULL && ret == 0)
409 				update_clear_conflict(cf);
410 			cvs_printf("M %s\n", cf->file_path);
411 		}
412 		break;
413 	case FILE_ADDED:
414 		cvs_printf("A %s\n", cf->file_path);
415 		break;
416 	case FILE_REMOVED:
417 		cvs_printf("R %s\n", cf->file_path);
418 		break;
419 	case FILE_CONFLICT:
420 		cvs_printf("C %s\n", cf->file_path);
421 		break;
422 	case FILE_LOST:
423 	case FILE_CHECKOUT:
424 	case FILE_PATCH:
425 		if (!reset_tag && (tag != NULL || cvs_specified_date != -1 ||
426 		    cvs_directory_date != -1 || (cf->file_ent != NULL &&
427 		    cf->file_ent->ce_tag != NULL)))
428 			flags = CO_SETSTICKY;
429 
430 		cvs_checkout_file(cf, cf->file_rcsrev, tag, flags);
431 		cvs_printf("U %s\n", cf->file_path);
432 		cvs_history_add(CVS_HISTORY_UPDATE_CO, cf, NULL);
433 		break;
434 	case FILE_MERGE:
435 		d3rev1 = cf->file_ent->ce_rev;
436 		d3rev2 = cf->file_rcsrev;
437 		cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_MERGE);
438 
439 		if (diff3_conflicts != 0) {
440 			cvs_printf("C %s\n", cf->file_path);
441 			cvs_history_add(CVS_HISTORY_UPDATE_MERGED_ERR,
442 			    cf, NULL);
443 		} else {
444 			update_clear_conflict(cf);
445 			cvs_printf("M %s\n", cf->file_path);
446 			cvs_history_add(CVS_HISTORY_UPDATE_MERGED, cf, NULL);
447 		}
448 		break;
449 	case FILE_UNLINK:
450 		(void)unlink(cf->file_path);
451 		if (cvs_server_active == 1)
452 			cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_REMOVE);
453 	case FILE_REMOVE_ENTRY:
454 		entlist = cvs_ent_open(cf->file_wd);
455 		cvs_ent_remove(entlist, cf->file_name);
456 		cvs_history_add(CVS_HISTORY_UPDATE_REMOVE, cf, NULL);
457 		break;
458 	case FILE_UPTODATE:
459 		if (cvs_cmdop != CVS_OP_UPDATE)
460 			break;
461 
462 		if (cf->file_rcsrev == NULL)
463 			break;
464 
465 		if (tag == NULL && cvs_specified_date == -1 &&
466 		    cvs_directory_date == -1 && !reset_tag &&
467 		    !reset_option)
468 			break;
469 
470 		if (cf->file_rcs->rf_dead != 1 &&
471 		    (cf->file_flags & FILE_HAS_TAG))
472 			cvs_checkout_file(cf, cf->file_rcsrev,
473 			    tag, CO_SETSTICKY);
474 		break;
475 	default:
476 		break;
477 	}
478 
479 	if (cvs_join_rev1 != NULL)
480 		update_join_file(cf);
481 }
482 
483 static void
484 update_clear_conflict(struct cvs_file *cf)
485 {
486 	CVSENTRIES *entlist;
487 	char *entry, revbuf[CVS_REV_BUFSZ];
488 	char sticky[CVS_ENT_MAXLINELEN], opt[4];
489 
490 	cvs_log(LP_TRACE, "update_clear_conflict(%s)", cf->file_path);
491 
492 	rcsnum_tostr(cf->file_rcsrev, revbuf, sizeof(revbuf));
493 
494 	sticky[0] = '\0';
495 	if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL)
496 		(void)xsnprintf(sticky, sizeof(sticky), "T%s",
497 		    cf->file_ent->ce_tag);
498 
499 	opt[0] = '\0';
500 	if (cf->file_ent != NULL && cf->file_ent->ce_opts != NULL)
501 		strlcpy(opt, cf->file_ent->ce_opts, sizeof(opt));
502 
503 	entry = xmalloc(CVS_ENT_MAXLINELEN);
504 	cvs_ent_line_str(cf->file_name, revbuf, "Result of merge",
505 	    opt[0] != '\0' ? opt : "", sticky, 0, 0,
506 	    entry, CVS_ENT_MAXLINELEN);
507 
508 	entlist = cvs_ent_open(cf->file_wd);
509 	cvs_ent_add(entlist, entry);
510 	xfree(entry);
511 }
512 
513 /*
514  * XXX - this is the way GNU cvs checks for outstanding conflicts
515  * in a file after a merge. It is a very very bad approach and
516  * should be looked at once opencvs is working decently.
517  */
518 int
519 update_has_conflict_markers(struct cvs_file *cf)
520 {
521 	BUF *bp;
522 	int conflict;
523 	char *content;
524 	struct cvs_line *lp;
525 	struct cvs_lines *lines;
526 	size_t len;
527 
528 	cvs_log(LP_TRACE, "update_has_conflict_markers(%s)", cf->file_path);
529 
530 	if (cf->fd == -1 || cf->file_ent == NULL)
531 		return (0);
532 
533 	bp = cvs_buf_load_fd(cf->fd);
534 
535 	cvs_buf_putc(bp, '\0');
536 	len = cvs_buf_len(bp);
537 	content = cvs_buf_release(bp);
538 	if ((lines = cvs_splitlines(content, len)) == NULL)
539 		fatal("update_has_conflict_markers: failed to split lines");
540 
541 	conflict = 0;
542 	TAILQ_FOREACH(lp, &(lines->l_lines), l_list) {
543 		if (lp->l_line == NULL)
544 			continue;
545 
546 		if (!strncmp(lp->l_line, RCS_CONFLICT_MARKER1,
547 		    sizeof(RCS_CONFLICT_MARKER1) - 1) ||
548 		    !strncmp(lp->l_line, RCS_CONFLICT_MARKER2,
549 		    sizeof(RCS_CONFLICT_MARKER2) - 1) ||
550 		    !strncmp(lp->l_line, RCS_CONFLICT_MARKER3,
551 		    sizeof(RCS_CONFLICT_MARKER3) - 1)) {
552 			conflict = 1;
553 			break;
554 		}
555 	}
556 
557 	cvs_freelines(lines);
558 	xfree(content);
559 	return (conflict);
560 }
561 
562 void
563 update_join_file(struct cvs_file *cf)
564 {
565 	int flag;
566 	time_t told;
567 	RCSNUM *rev1, *rev2;
568 	const char *state1, *state2;
569 	char rbuf[CVS_REV_BUFSZ], *jrev1, *jrev2, *p;
570 
571 	rev1 = rev2 = NULL;
572 	jrev1 = jrev2 = NULL;
573 
574 	jrev1 = xstrdup(cvs_join_rev1);
575 	if (cvs_join_rev2 != NULL)
576 		jrev2 = xstrdup(cvs_join_rev2);
577 
578 	if (jrev2 == NULL) {
579 		jrev2 = jrev1;
580 		jrev1 = NULL;
581 	}
582 
583 	told = cvs_specified_date;
584 
585 	if ((p = strchr(jrev2, ':')) != NULL) {
586 		(*p++) = '\0';
587 		cvs_specified_date = cvs_date_parse(p);
588 	}
589 
590 	rev2 = rcs_translate_tag(jrev2, cf->file_rcs);
591 	cvs_specified_date = told;
592 
593 	if (jrev1 != NULL) {
594 		if ((p = strchr(jrev1, ':')) != NULL) {
595 			(*p++) = '\0';
596 			cvs_specified_date = cvs_date_parse(p);
597 		}
598 
599 		rev1 = rcs_translate_tag(jrev1, cf->file_rcs);
600 		cvs_specified_date = told;
601 	} else {
602 		if (rev2 == NULL)
603 			goto out;
604 
605 		rev1 = rcsnum_alloc();
606 		rcsnum_cpy(cf->file_rcsrev, rev1, 0);
607 	}
608 
609 	state1 = state2 = RCS_STATE_DEAD;
610 
611 	if (rev1 != NULL)
612 		state1 = rcs_state_get(cf->file_rcs, rev1);
613 	if (rev2 != NULL)
614 		state2 = rcs_state_get(cf->file_rcs, rev2);
615 
616 	if (rev2 == NULL || !strcmp(state2, RCS_STATE_DEAD)) {
617 		if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD))
618 			goto out;
619 
620 		if (cf->file_status == FILE_REMOVED ||
621 		    cf->file_rcs->rf_dead == 1)
622 			goto out;
623 
624 		if (cf->file_status == FILE_MODIFIED ||
625 		    cf->file_status == FILE_ADDED)
626 			goto out;
627 
628 		(void)unlink(cf->file_path);
629 		(void)close(cf->fd);
630 		cf->fd = -1;
631 		cvs_remove_local(cf);
632 		goto out;
633 	}
634 
635 	if (cf->file_ent != NULL) {
636 		if (!rcsnum_cmp(cf->file_ent->ce_rev, rev2, 0))
637 			goto out;
638 	}
639 
640 	if (cf->file_rcsrev == NULL) {
641 		cvs_printf("non-mergable file: %s has no head revision!\n",
642 		    cf->file_path);
643 		goto out;
644 	}
645 
646 	if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) {
647 		if (cf->fd != -1) {
648 			cvs_printf("%s exists but has been added in %s\n",
649 			    cf->file_path, jrev2);
650 		} else {
651 			cvs_printf("A %s\n", cf->file_path);
652 			cvs_checkout_file(cf, cf->file_rcsrev, NULL, 0);
653 			cvs_add_local(cf);
654 		}
655 		goto out;
656 	}
657 
658 	if (!rcsnum_cmp(rev1, rev2, 0))
659 		goto out;
660 
661 	if (cf->fd == -1) {
662 		cvs_printf("%s does not exist but is present in %s\n",
663 		    cf->file_path, jrev2);
664 		goto out;
665 	}
666 
667 	flag = rcs_kwexp_get(cf->file_rcs);
668 	if (flag & RCS_KWEXP_NONE) {
669 		cvs_printf("non-mergable file: %s needs merge!\n",
670 		    cf->file_path);
671 		goto out;
672 	}
673 
674 	cvs_printf("joining ");
675 	rcsnum_tostr(rev1, rbuf, sizeof(rbuf));
676 	cvs_printf("%s ", rbuf);
677 
678 	rcsnum_tostr(rev2, rbuf, sizeof(rbuf));
679 	cvs_printf("%s ", rbuf);
680 
681 	rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf));
682 	cvs_printf("into %s (%s)\n", cf->file_path, rbuf);
683 
684 	d3rev1 = rev1;
685 	d3rev2 = rev2;
686 	cvs_checkout_file(cf, cf->file_rcsrev, NULL, CO_MERGE);
687 
688 	if (diff3_conflicts == 0)
689 		update_clear_conflict(cf);
690 
691 out:
692 	if (rev1 != NULL)
693 		rcsnum_free(rev1);
694 	if (rev2 != NULL)
695 		rcsnum_free(rev2);
696 
697 	if (jrev1 != NULL)
698 		xfree(jrev1);
699 	if (jrev2 != NULL)
700 		xfree(jrev2);
701 }
702