xref: /openbsd-src/gnu/usr.bin/cvs/src/update.c (revision 2e5b458aebc823a1a661ba48290a70846e2c4628)
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  * "update" updates the version in the present directory with respect to the RCS
9  * repository.  The present version must have been created by "checkout". The
10  * user can keep up-to-date by calling "update" whenever he feels like it.
11  *
12  * The present version can be committed by "commit", but this keeps the version
13  * in tact.
14  *
15  * Arguments following the options are taken to be file names to be updated,
16  * rather than updating the entire directory.
17  *
18  * Modified or non-existent RCS files are checked out and reported as U
19  * <user_file>
20  *
21  * Modified user files are reported as M <user_file>.  If both the RCS file and
22  * the user file have been modified, the user file is replaced by the result
23  * of rcsmerge, and a backup file is written for the user in .#file.version.
24  * If this throws up irreconcilable differences, the file is reported as C
25  * <user_file>, and as M <user_file> otherwise.
26  *
27  * Files added but not yet committed are reported as A <user_file>. Files
28  * removed but not yet committed are reported as R <user_file>.
29  *
30  * If the current directory contains subdirectories that hold concurrent
31  * versions, these are updated too.  If the -d option was specified, new
32  * directories added to the repository are automatically created and updated
33  * as well.
34  */
35 
36 #include "cvs.h"
37 #include "savecwd.h"
38 #ifdef SERVER_SUPPORT
39 #include "md5.h"
40 #endif
41 #include "watch.h"
42 #include "fileattr.h"
43 #include "edit.h"
44 #include "getline.h"
45 #include "buffer.h"
46 #include "hardlink.h"
47 
48 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
49 				 int adding, int merging, int update_server));
50 #ifdef SERVER_SUPPORT
51 static void checkout_to_buffer PROTO ((void *, const char *, size_t));
52 #endif
53 #ifdef SERVER_SUPPORT
54 static int patch_file PROTO ((struct file_info *finfo,
55 			      Vers_TS *vers_ts,
56 			      int *docheckout, struct stat *file_info,
57 			      unsigned char *checksum));
58 static void patch_file_write PROTO ((void *, const char *, size_t));
59 #endif
60 static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
61 static int scratch_file PROTO((struct file_info *finfo));
62 static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir,
63 					char *repository, char *update_dir,
64 					List *entries));
65 static int update_dirleave_proc PROTO ((void *callerdat, char *dir,
66 					int err, char *update_dir,
67 					List *entries));
68 static int update_fileproc PROTO ((void *callerdat, struct file_info *));
69 static int update_filesdone_proc PROTO ((void *callerdat, int err,
70 					 char *repository, char *update_dir,
71 					 List *entries));
72 #ifdef PRESERVE_PERMISSIONS_SUPPORT
73 static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *));
74 #endif
75 static void write_letter PROTO ((struct file_info *finfo, int letter));
76 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
77 
78 static char *options = NULL;
79 static char *tag = NULL;
80 static char *date = NULL;
81 /* This is a bit of a kludge.  We call WriteTag at the beginning
82    before we know whether nonbranch is set or not.  And then at the
83    end, once we have the right value for nonbranch, we call WriteTag
84    again.  I don't know whether the first call is necessary or not.
85    rewrite_tag is nonzero if we are going to have to make that second
86    call.  */
87 static int rewrite_tag;
88 static int nonbranch;
89 
90 /* If we set the tag or date for a subdirectory, we use this to undo
91    the setting.  See update_dirent_proc.  */
92 static char *tag_update_dir;
93 
94 static char *join_rev1, *date_rev1;
95 static char *join_rev2, *date_rev2;
96 static int aflag = 0;
97 static int force_tag_match = 1;
98 static int update_build_dirs = 0;
99 static int update_prune_dirs = 0;
100 static int pipeout = 0;
101 #ifdef SERVER_SUPPORT
102 static int patches = 0;
103 static int rcs_diff_patches = 0;
104 #endif
105 static List *ignlist = (List *) NULL;
106 static time_t last_register_time;
107 static const char *const update_usage[] =
108 {
109     "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n",
110     "    [-I ign] [-W spec] [files...]\n",
111     "\t-A\tReset any sticky tags/date/kopts.\n",
112     "\t-P\tPrune empty directories.\n",
113     "\t-d\tBuild directories, like checkout does.\n",
114     "\t-f\tForce a head revision match if tag/date not found.\n",
115     "\t-l\tLocal directory only, no recursion.\n",
116     "\t-R\tProcess directories recursively.\n",
117     "\t-p\tSend updates to standard output (avoids stickiness).\n",
118     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
119     "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
120     "\t-D date\tSet date to update from (is sticky).\n",
121     "\t-j rev\tMerge in changes made between current revision and rev.\n",
122     "\t-I ign\tMore files to ignore (! to reset).\n",
123     "\t-W spec\tWrappers specification line.\n",
124     "(Specify the --help global option for a list of other help options)\n",
125     NULL
126 };
127 
128 /*
129  * update is the argv,argc based front end for arg parsing
130  */
131 int
132 update (argc, argv)
133     int argc;
134     char **argv;
135 {
136     int c, err;
137     int local = 0;			/* recursive by default */
138     int which;				/* where to look for files and dirs */
139 
140     if (argc == -1)
141 	usage (update_usage);
142 
143     ign_setup ();
144     wrap_setup ();
145 
146     /* parse the args */
147     optind = 0;
148     while ((c = getopt (argc, argv, "+ApPflRQqduk:r:D:j:I:W:")) != -1)
149     {
150 	switch (c)
151 	{
152 	    case 'A':
153 		aflag = 1;
154 		break;
155 	    case 'I':
156 		ign_add (optarg, 0);
157 		break;
158 	    case 'W':
159 		wrap_add (optarg, 0);
160 		break;
161 	    case 'k':
162 		if (options)
163 		    free (options);
164 		options = RCS_check_kflag (optarg);
165 		break;
166 	    case 'l':
167 		local = 1;
168 		break;
169 	    case 'R':
170 		local = 0;
171 		break;
172 	    case 'Q':
173 	    case 'q':
174 #ifdef SERVER_SUPPORT
175 		/* The CVS 1.5 client sends these options (in addition to
176 		   Global_option requests), so we must ignore them.  */
177 		if (!server_active)
178 #endif
179 		    error (1, 0,
180 			   "-q or -Q must be specified before \"%s\"",
181 			   command_name);
182 		break;
183 	    case 'd':
184 		update_build_dirs = 1;
185 		break;
186 	    case 'f':
187 		force_tag_match = 0;
188 		break;
189 	    case 'r':
190 		tag = optarg;
191 		break;
192 	    case 'D':
193 		date = Make_Date (optarg);
194 		break;
195 	    case 'P':
196 		update_prune_dirs = 1;
197 		break;
198 	    case 'p':
199 		pipeout = 1;
200 		noexec = 1;		/* so no locks will be created */
201 		break;
202 	    case 'j':
203 		if (join_rev2)
204 		    error (1, 0, "only two -j options can be specified");
205 		if (join_rev1)
206 		    join_rev2 = optarg;
207 		else
208 		    join_rev1 = optarg;
209 		break;
210 	    case 'u':
211 #ifdef SERVER_SUPPORT
212 		if (server_active)
213 		{
214 		    patches = 1;
215 		    rcs_diff_patches = server_use_rcs_diff ();
216 		}
217 		else
218 #endif
219 		    usage (update_usage);
220 		break;
221 	    case '?':
222 	    default:
223 		usage (update_usage);
224 		break;
225 	}
226     }
227     argc -= optind;
228     argv += optind;
229 
230 #ifdef CLIENT_SUPPORT
231     if (client_active)
232     {
233 	int pass;
234 
235 	/* The first pass does the regular update.  If we receive at least
236 	   one patch which failed, we do a second pass and just fetch
237 	   those files whose patches failed.  */
238 	pass = 1;
239 	do
240 	{
241 	    int status;
242 
243 	    start_server ();
244 
245 	    if (local)
246 		send_arg("-l");
247 	    if (update_build_dirs)
248 		send_arg("-d");
249 	    if (pipeout)
250 		send_arg("-p");
251 	    if (!force_tag_match)
252 		send_arg("-f");
253 	    if (aflag)
254 		send_arg("-A");
255 	    if (update_prune_dirs)
256 		send_arg("-P");
257 	    client_prune_dirs = update_prune_dirs;
258 	    option_with_arg ("-r", tag);
259 	    if (options && options[0] != '\0')
260 		send_arg (options);
261 	    if (date)
262 		client_senddate (date);
263 	    if (join_rev1)
264 		option_with_arg ("-j", join_rev1);
265 	    if (join_rev2)
266 		option_with_arg ("-j", join_rev2);
267 	    wrap_send ();
268 
269 	    /* If the server supports the command "update-patches", that means
270 	       that it knows how to handle the -u argument to update, which
271 	       means to send patches instead of complete files.
272 
273 	       We don't send -u if failed_patches != NULL, so that the
274 	       server doesn't try to send patches which will just fail
275 	       again.  At least currently, the client also clobbers the
276 	       file and tells the server it is lost, which also will get
277 	       a full file instead of a patch, but it seems clean to omit
278 	       -u.  */
279 	    if (failed_patches == NULL)
280 	    {
281 		if (supported_request ("update-patches"))
282 		    send_arg ("-u");
283 	    }
284 
285 	    if (failed_patches == NULL)
286 	    {
287 		send_file_names (argc, argv, SEND_EXPAND_WILD);
288 		/* If noexec, probably could be setting SEND_NO_CONTENTS.
289 		   Same caveats as for "cvs status" apply.  */
290 		send_files (argc, argv, local, aflag,
291 			    update_build_dirs ? SEND_BUILD_DIRS : 0);
292 	    }
293 	    else
294 	    {
295 		int i;
296 
297 		(void) printf ("%s client: refetching unpatchable files\n",
298 			       program_name);
299 
300 		if (toplevel_wd != NULL
301 		    && CVS_CHDIR (toplevel_wd) < 0)
302 		{
303 		    error (1, errno, "could not chdir to %s", toplevel_wd);
304 		}
305 
306 		for (i = 0; i < failed_patches_count; i++)
307 		    (void) unlink_file (failed_patches[i]);
308 		send_file_names (failed_patches_count, failed_patches, 0);
309 		send_files (failed_patches_count, failed_patches, local,
310 			    aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
311 	    }
312 
313 	    failed_patches = NULL;
314 	    failed_patches_count = 0;
315 
316 	    send_to_server ("update\012", 0);
317 
318 	    status = get_responses_and_close ();
319 
320 	    /* If there are any conflicts, the server will return a
321                non-zero exit status.  If any patches failed, we still
322                want to run the update again.  We use a pass count to
323                avoid an endless loop.  */
324 
325 	    /* Notes: (1) assuming that status != 0 implies a
326 	       potential conflict is the best we can cleanly do given
327 	       the current protocol.  I suppose that trying to
328 	       re-fetch in cases where there was a more serious error
329 	       is probably more or less harmless, but it isn't really
330 	       ideal.  (2) it would be nice to have a testsuite case for the
331 	       conflict-and-patch-failed case.  */
332 
333 	    if (status != 0
334 		&& (failed_patches == NULL || pass > 1))
335 	    {
336 		return status;
337 	    }
338 
339 	    ++pass;
340 	} while (failed_patches != NULL);
341 
342 	return 0;
343     }
344 #endif
345 
346     if (tag != NULL)
347 	tag_check_valid (tag, argc, argv, local, aflag, "");
348     if (join_rev1 != NULL)
349         tag_check_valid_join (join_rev1, argc, argv, local, aflag, "");
350     if (join_rev2 != NULL)
351         tag_check_valid_join (join_rev2, argc, argv, local, aflag, "");
352 
353     /*
354      * If we are updating the entire directory (for real) and building dirs
355      * as we go, we make sure there is no static entries file and write the
356      * tag file as appropriate
357      */
358     if (argc <= 0 && !pipeout)
359     {
360 	if (update_build_dirs)
361 	{
362 	    if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
363 		error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
364 #ifdef SERVER_SUPPORT
365 	    if (server_active)
366 		server_clear_entstat (".", Name_Repository (NULL, NULL));
367 #endif
368 	}
369 
370 	/* keep the CVS/Tag file current with the specified arguments */
371 	if (aflag || tag || date)
372 	{
373 	    WriteTag ((char *) NULL, tag, date, 0,
374 		      ".", Name_Repository (NULL, NULL));
375 	    rewrite_tag = 1;
376 	    nonbranch = 0;
377 	}
378     }
379 
380     /* look for files/dirs locally and in the repository */
381     which = W_LOCAL | W_REPOS;
382 
383     /* look in the attic too if a tag or date is specified */
384     if (tag != NULL || date != NULL || joining())
385 	which |= W_ATTIC;
386 
387     /* call the command line interface */
388     err = do_update (argc, argv, options, tag, date, force_tag_match,
389 		     local, update_build_dirs, aflag, update_prune_dirs,
390 		     pipeout, which, join_rev1, join_rev2, (char *) NULL);
391 
392     /* free the space Make_Date allocated if necessary */
393     if (date != NULL)
394 	free (date);
395 
396     return (err);
397 }
398 
399 /*
400  * Command line interface to update (used by checkout)
401  */
402 int
403 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
404 	   xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir)
405     int argc;
406     char **argv;
407     char *xoptions;
408     char *xtag;
409     char *xdate;
410     int xforce;
411     int local;
412     int xbuild;
413     int xaflag;
414     int xprune;
415     int xpipeout;
416     int which;
417     char *xjoin_rev1;
418     char *xjoin_rev2;
419     char *preload_update_dir;
420 {
421     int err = 0;
422     char *cp;
423 
424     /* fill in the statics */
425     options = xoptions;
426     tag = xtag;
427     date = xdate;
428     force_tag_match = xforce;
429     update_build_dirs = xbuild;
430     aflag = xaflag;
431     update_prune_dirs = xprune;
432     pipeout = xpipeout;
433 
434     /* setup the join support */
435     join_rev1 = xjoin_rev1;
436     join_rev2 = xjoin_rev2;
437     if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
438     {
439 	*cp++ = '\0';
440 	date_rev1 = Make_Date (cp);
441     }
442     else
443 	date_rev1 = (char *) NULL;
444     if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
445     {
446 	*cp++ = '\0';
447 	date_rev2 = Make_Date (cp);
448     }
449     else
450 	date_rev2 = (char *) NULL;
451 
452 #ifdef PRESERVE_PERMISSIONS_SUPPORT
453     if (preserve_perms)
454     {
455 	/* We need to do an extra recursion, bleah.  It's to make sure
456 	   that we know as much as possible about file linkage. */
457 	hardlist = getlist();
458 	working_dir = xgetwd();		/* save top-level working dir */
459 
460 	/* FIXME-twp: the arguments to start_recursion make me dizzy.  This
461 	   function call was copied from the update_fileproc call that
462 	   follows it; someone should make sure that I did it right. */
463 	err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL,
464 			       (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
465 			       argc, argv, local, which, aflag, 1,
466 			       preload_update_dir, 1);
467 	if (err)
468 	    return (err);
469 
470 	/* FIXME-twp: at this point we should walk the hardlist
471 	   and update the `links' field of each hardlink_info struct
472 	   to list the files that are linked on dist.  That would make
473 	   it easier & more efficient to compare the disk linkage with
474 	   the repository linkage (a simple strcmp). */
475     }
476 #endif
477 
478     /* call the recursion processor */
479     err = start_recursion (update_fileproc, update_filesdone_proc,
480 			   update_dirent_proc, update_dirleave_proc, NULL,
481 			   argc, argv, local, which, aflag, 1,
482 			   preload_update_dir, 1);
483 
484     /* see if we need to sleep before returning */
485     if (last_register_time)
486     {
487 	time_t now;
488 
489 	(void) time (&now);
490 	if (now == last_register_time)
491 	    sleep (1);			/* to avoid time-stamp races */
492     }
493 
494     return (err);
495 }
496 
497 #ifdef PRESERVE_PERMISSIONS_SUPPORT
498 /*
499  * The get_linkinfo_proc callback adds each file to the hardlist
500  * (see hardlink.c).
501  */
502 
503 static int
504 get_linkinfo_proc (callerdat, finfo)
505     void *callerdat;
506     struct file_info *finfo;
507 {
508     char *fullpath;
509     Node *linkp;
510     struct hardlink_info *hlinfo;
511 
512     /* Get the full pathname of the current file. */
513     fullpath = xmalloc (strlen(working_dir) +
514 			strlen(finfo->fullname) + 2);
515     sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
516 
517     /* To permit recursing into subdirectories, files
518        are keyed on the full pathname and not on the basename. */
519     linkp = lookup_file_by_inode (fullpath);
520     if (linkp == NULL)
521     {
522 	/* The file isn't on disk; we are probably restoring
523 	   a file that was removed. */
524 	return 0;
525     }
526 
527     /* Create a new, empty hardlink_info node. */
528     hlinfo = (struct hardlink_info *)
529 	xmalloc (sizeof (struct hardlink_info));
530 
531     hlinfo->status = (Ctype) 0;	/* is this dumb? */
532     hlinfo->checked_out = 0;
533 
534     linkp->data = (char *) hlinfo;
535 
536     return 0;
537 }
538 #endif
539 
540 /*
541  * This is the callback proc for update.  It is called for each file in each
542  * directory by the recursion code.  The current directory is the local
543  * instantiation.  file is the file name we are to operate on. update_dir is
544  * set to the path relative to where we started (for pretty printing).
545  * repository is the repository. entries and srcfiles are the pre-parsed
546  * entries and source control files.
547  *
548  * This routine decides what needs to be done for each file and does the
549  * appropriate magic for checkout
550  */
551 static int
552 update_fileproc (callerdat, finfo)
553     void *callerdat;
554     struct file_info *finfo;
555 {
556     int retval;
557     Ctype status;
558     Vers_TS *vers;
559     int resurrecting;
560 
561     resurrecting = 0;
562 
563     status = Classify_File (finfo, tag, date, options, force_tag_match,
564 			    aflag, &vers, pipeout);
565 
566     /* Keep track of whether TAG is a branch tag.
567        Note that if it is a branch tag in some files and a nonbranch tag
568        in others, treat it as a nonbranch tag.  It is possible that case
569        should elicit a warning or an error.  */
570     if (rewrite_tag
571 	&& tag != NULL
572 	&& finfo->rcs != NULL)
573     {
574 	char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
575 	if (rev != NULL
576 	    && !RCS_nodeisbranch (finfo->rcs, tag))
577 	    nonbranch = 1;
578 	if (rev != NULL)
579 	    free (rev);
580     }
581 
582     if (pipeout)
583     {
584 	/*
585 	 * We just return success without doing anything if any of the really
586 	 * funky cases occur
587 	 *
588 	 * If there is still a valid RCS file, do a regular checkout type
589 	 * operation
590 	 */
591 	switch (status)
592 	{
593 	    case T_UNKNOWN:		/* unknown file was explicitly asked
594 					 * about */
595 	    case T_REMOVE_ENTRY:	/* needs to be un-registered */
596 	    case T_ADDED:		/* added but not committed */
597 		retval = 0;
598 		break;
599 	    case T_CONFLICT:		/* old punt-type errors */
600 		retval = 1;
601 		break;
602 	    case T_UPTODATE:		/* file was already up-to-date */
603 	    case T_NEEDS_MERGE:		/* needs merging */
604 	    case T_MODIFIED:		/* locally modified */
605 	    case T_REMOVED:		/* removed but not committed */
606 	    case T_CHECKOUT:		/* needs checkout */
607 #ifdef SERVER_SUPPORT
608 	    case T_PATCH:		/* needs patch */
609 #endif
610 		retval = checkout_file (finfo, vers, 0, 0, 0);
611 		break;
612 
613 	    default:			/* can't ever happen :-) */
614 		error (0, 0,
615 		       "unknown file status %d for file %s", status, finfo->file);
616 		retval = 0;
617 		break;
618 	}
619     }
620     else
621     {
622 	switch (status)
623 	{
624 	    case T_UNKNOWN:		/* unknown file was explicitly asked
625 					 * about */
626 	    case T_UPTODATE:		/* file was already up-to-date */
627 		retval = 0;
628 		break;
629 	    case T_CONFLICT:		/* old punt-type errors */
630 		retval = 1;
631 		write_letter (finfo, 'C');
632 		break;
633 	    case T_NEEDS_MERGE:		/* needs merging */
634 		if (noexec)
635 		{
636 		    retval = 1;
637 		    write_letter (finfo, 'C');
638 		}
639 		else
640 		{
641 		    retval = merge_file (finfo, vers);
642 		}
643 		break;
644 	    case T_MODIFIED:		/* locally modified */
645 		retval = 0;
646 		if (vers->ts_conflict)
647 		{
648 		    char *filestamp;
649 		    int retcode;
650 
651 		    /*
652 		     * If the timestamp has changed and no conflict indicators
653 		     * are found, it isn't a 'C' any more.
654 		     */
655 #ifdef SERVER_SUPPORT
656 		    if (server_active)
657 			retcode = vers->ts_conflict[0] != '=';
658 		    else {
659 			filestamp = time_stamp (finfo->file);
660 			retcode = strcmp (vers->ts_conflict, filestamp);
661 			free (filestamp);
662 		    }
663 #else
664 		    filestamp = time_stamp (finfo->file);
665 		    retcode = strcmp (vers->ts_conflict, filestamp);
666 		    free (filestamp);
667 #endif
668 
669 		    if (retcode)
670 		    {
671 			/* The timestamps differ.  But if there are conflict
672 			   markers print 'C' anyway.  */
673 			retcode = !file_has_markers (finfo);
674 		    }
675 
676 		    if (!retcode)
677 		    {
678 			write_letter (finfo, 'C');
679 			retval = 1;
680 		    }
681 		    else
682 		    {
683 			/* Reregister to clear conflict flag. */
684 			Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs,
685 				  vers->options, vers->tag,
686 				  vers->date, (char *)0);
687 		    }
688 		}
689 		if (!retval)
690 		{
691 		    write_letter (finfo, 'M');
692 		    retval = 0;
693 		}
694 		break;
695 #ifdef SERVER_SUPPORT
696 	    case T_PATCH:		/* needs patch */
697 		if (patches)
698 		{
699 		    int docheckout;
700 		    struct stat file_info;
701 		    unsigned char checksum[16];
702 
703 		    retval = patch_file (finfo,
704 					 vers, &docheckout,
705 					 &file_info, checksum);
706 		    if (! docheckout)
707 		    {
708 		        if (server_active && retval == 0)
709 			    server_updated (finfo, vers,
710 					    (rcs_diff_patches
711 					     ? SERVER_RCS_DIFF
712 					     : SERVER_PATCHED),
713 					    file_info.st_mode, checksum,
714 					    (struct buffer *) NULL);
715 			break;
716 		    }
717 		}
718 		/* If we're not running as a server, just check the
719 		   file out.  It's simpler and faster than producing
720 		   and applying patches.  */
721 		/* Fall through.  */
722 #endif
723 	    case T_CHECKOUT:		/* needs checkout */
724 		retval = checkout_file (finfo, vers, 0, 0, 1);
725 		break;
726 	    case T_ADDED:		/* added but not committed */
727 		write_letter (finfo, 'A');
728 		retval = 0;
729 		break;
730 	    case T_REMOVED:		/* removed but not committed */
731 		write_letter (finfo, 'R');
732 		retval = 0;
733 		break;
734 	    case T_REMOVE_ENTRY:	/* needs to be un-registered */
735 		retval = scratch_file (finfo);
736 #ifdef SERVER_SUPPORT
737 		if (server_active && retval == 0)
738 		{
739 		    if (vers->ts_user == NULL)
740 			server_scratch_entry_only ();
741 		    server_updated (finfo, vers,
742 				    SERVER_UPDATED, (mode_t) -1,
743 				    (unsigned char *) NULL,
744 				    (struct buffer *) NULL);
745 		}
746 #endif
747 		break;
748 	    default:			/* can't ever happen :-) */
749 		error (0, 0,
750 		       "unknown file status %d for file %s", status, finfo->file);
751 		retval = 0;
752 		break;
753 	}
754     }
755 
756     /* only try to join if things have gone well thus far */
757     if (retval == 0 && join_rev1)
758 	join_file (finfo, vers);
759 
760     /* if this directory has an ignore list, add this file to it */
761     if (ignlist)
762     {
763 	Node *p;
764 
765 	p = getnode ();
766 	p->type = FILES;
767 	p->key = xstrdup (finfo->file);
768 	if (addnode (ignlist, p) != 0)
769 	    freenode (p);
770     }
771 
772     freevers_ts (&vers);
773     return (retval);
774 }
775 
776 static void update_ignproc PROTO ((char *, char *));
777 
778 static void
779 update_ignproc (file, dir)
780     char *file;
781     char *dir;
782 {
783     struct file_info finfo;
784 
785     memset (&finfo, 0, sizeof (finfo));
786     finfo.file = file;
787     finfo.update_dir = dir;
788     if (dir[0] == '\0')
789 	finfo.fullname = xstrdup (file);
790     else
791     {
792 	finfo.fullname = xmalloc (strlen (file) + strlen (dir) + 10);
793 	strcpy (finfo.fullname, dir);
794 	strcat (finfo.fullname, "/");
795 	strcat (finfo.fullname, file);
796     }
797 
798     write_letter (&finfo, '?');
799     free (finfo.fullname);
800 }
801 
802 /* ARGSUSED */
803 static int
804 update_filesdone_proc (callerdat, err, repository, update_dir, entries)
805     void *callerdat;
806     int err;
807     char *repository;
808     char *update_dir;
809     List *entries;
810 {
811     if (rewrite_tag)
812     {
813 	WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
814 	rewrite_tag = 0;
815     }
816 
817     /* if this directory has an ignore list, process it then free it */
818     if (ignlist)
819     {
820 	ignore_files (ignlist, entries, update_dir, update_ignproc);
821 	dellist (&ignlist);
822     }
823 
824     /* Clean up CVS admin dirs if we are export */
825     if (strcmp (command_name, "export") == 0)
826     {
827 	/* I'm not sure the existence_error is actually possible (except
828 	   in cases where we really should print a message), but since
829 	   this code used to ignore all errors, I'll play it safe.  */
830 	if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
831 	    error (0, errno, "cannot remove %s directory", CVSADM);
832     }
833 #ifdef SERVER_SUPPORT
834     else if (!server_active && !pipeout)
835 #else
836     else if (!pipeout)
837 #endif /* SERVER_SUPPORT */
838     {
839         /* If there is no CVS/Root file, add one */
840         if (!isfile (CVSADM_ROOT))
841 	    Create_Root ((char *) NULL, CVSroot_original);
842     }
843 
844     return (err);
845 }
846 
847 /*
848  * update_dirent_proc () is called back by the recursion processor before a
849  * sub-directory is processed for update.  In this case, update_dirent proc
850  * will probably create the directory unless -d isn't specified and this is a
851  * new directory.  A return code of 0 indicates the directory should be
852  * processed by the recursion code.  A return of non-zero indicates the
853  * recursion code should skip this directory.
854  */
855 static Dtype
856 update_dirent_proc (callerdat, dir, repository, update_dir, entries)
857     void *callerdat;
858     char *dir;
859     char *repository;
860     char *update_dir;
861     List *entries;
862 {
863     if (ignore_directory (update_dir))
864     {
865 	/* print the warm fuzzy message */
866 	if (!quiet)
867 	  error (0, 0, "Ignoring %s", update_dir);
868         return R_SKIP_ALL;
869     }
870 
871     if (!isdir (dir))
872     {
873 	/* if we aren't building dirs, blow it off */
874 	if (!update_build_dirs)
875 	    return (R_SKIP_ALL);
876 
877 	if (noexec)
878 	{
879 	    /* ignore the missing dir if -n is specified */
880 	    error (0, 0, "New directory `%s' -- ignored", update_dir);
881 	    return (R_SKIP_ALL);
882 	}
883 	else
884 	{
885 	    /* otherwise, create the dir and appropriate adm files */
886 
887 	    /* If no tag or date were specified on the command line,
888                and we're not using -A, we want the subdirectory to use
889                the tag and date, if any, of the current directory.
890                That way, update -d will work correctly when working on
891                a branch.
892 
893 	       We use TAG_UPDATE_DIR to undo the tag setting in
894 	       update_dirleave_proc.  If we did not do this, we would
895 	       not correctly handle a working directory with multiple
896 	       tags (and maybe we should prohibit such working
897 	       directories, but they work now and we shouldn't make
898 	       them stop working without more thought).  */
899 	    if ((tag == NULL && date == NULL) && ! aflag)
900 	    {
901 		ParseTag (&tag, &date, &nonbranch);
902 		if (tag != NULL || date != NULL)
903 		    tag_update_dir = xstrdup (update_dir);
904 	    }
905 
906 	    make_directory (dir);
907 	    Create_Admin (dir, update_dir, repository, tag, date,
908 			  /* This is a guess.  We will rewrite it later
909 			     via WriteTag.  */
910 			  0,
911 			  0);
912 	    rewrite_tag = 1;
913 	    nonbranch = 0;
914 	    Subdir_Register (entries, (char *) NULL, dir);
915 	}
916     }
917     /* Do we need to check noexec here? */
918     else if (!pipeout)
919     {
920 	char *cvsadmdir;
921 
922 	/* The directory exists.  Check to see if it has a CVS
923 	   subdirectory.  */
924 
925 	cvsadmdir = xmalloc (strlen (dir) + 80);
926 	strcpy (cvsadmdir, dir);
927 	strcat (cvsadmdir, "/");
928 	strcat (cvsadmdir, CVSADM);
929 
930 	if (!isdir (cvsadmdir))
931 	{
932 	    /* We cannot successfully recurse into a directory without a CVS
933 	       subdirectory.  Generally we will have already printed
934 	       "? foo".  */
935 	    free (cvsadmdir);
936 	    return R_SKIP_ALL;
937 	}
938 	free (cvsadmdir);
939     }
940 
941     /*
942      * If we are building dirs and not going to stdout, we make sure there is
943      * no static entries file and write the tag file as appropriate
944      */
945     if (!pipeout)
946     {
947 	if (update_build_dirs)
948 	{
949 	    char *tmp;
950 
951 	    tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10);
952 	    (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
953 	    if (unlink_file (tmp) < 0 && ! existence_error (errno))
954 		error (1, errno, "cannot remove file %s", tmp);
955 #ifdef SERVER_SUPPORT
956 	    if (server_active)
957 		server_clear_entstat (update_dir, repository);
958 #endif
959 	    free (tmp);
960 	}
961 
962 	/* keep the CVS/Tag file current with the specified arguments */
963 	if (aflag || tag || date)
964 	{
965 	    WriteTag (dir, tag, date, 0, update_dir, repository);
966 	    rewrite_tag = 1;
967 	    nonbranch = 0;
968 	}
969 
970 	/* initialize the ignore list for this directory */
971 	ignlist = getlist ();
972     }
973 
974     /* print the warm fuzzy message */
975     if (!quiet)
976 	error (0, 0, "Updating %s", update_dir);
977 
978     return (R_PROCESS);
979 }
980 
981 /*
982  * update_dirleave_proc () is called back by the recursion code upon leaving
983  * a directory.  It will prune empty directories if needed and will execute
984  * any appropriate update programs.
985  */
986 /* ARGSUSED */
987 static int
988 update_dirleave_proc (callerdat, dir, err, update_dir, entries)
989     void *callerdat;
990     char *dir;
991     int err;
992     char *update_dir;
993     List *entries;
994 {
995     FILE *fp;
996 
997     /* If we set the tag or date for a new subdirectory in
998        update_dirent_proc, and we're now done with that subdirectory,
999        undo the tag/date setting.  Note that we know that the tag and
1000        date were both originally NULL in this case.  */
1001     if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
1002     {
1003 	if (tag != NULL)
1004 	{
1005 	    free (tag);
1006 	    tag = NULL;
1007 	}
1008 	if (date != NULL)
1009 	{
1010 	    free (date);
1011 	    date = NULL;
1012 	}
1013 	nonbranch = 0;
1014 	free (tag_update_dir);
1015 	tag_update_dir = NULL;
1016     }
1017 
1018     /* run the update_prog if there is one */
1019     /* FIXME: should be checking for errors from CVS_FOPEN and printing
1020        them if not existence_error.  */
1021     if (err == 0 && !pipeout && !noexec &&
1022 	(fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL)
1023     {
1024 	char *cp;
1025 	char *repository;
1026 	char *line = NULL;
1027 	size_t line_allocated = 0;
1028 
1029 	repository = Name_Repository ((char *) NULL, update_dir);
1030 	if (getline (&line, &line_allocated, fp) >= 0)
1031 	{
1032 	    if ((cp = strrchr (line, '\n')) != NULL)
1033 		*cp = '\0';
1034 	    run_setup (line);
1035 	    run_arg (repository);
1036 	    cvs_output (program_name, 0);
1037 	    cvs_output (" ", 1);
1038 	    cvs_output (command_name, 0);
1039 	    cvs_output (": Executing '", 0);
1040 	    run_print (stdout);
1041 	    cvs_output ("'\n", 0);
1042 	    (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
1043 	}
1044 	else if (ferror (fp))
1045 	    error (0, errno, "cannot read %s", CVSADM_UPROG);
1046 	else
1047 	    error (0, 0, "unexpected end of file on %s", CVSADM_UPROG);
1048 
1049 	if (fclose (fp) < 0)
1050 	    error (0, errno, "cannot close %s", CVSADM_UPROG);
1051 	if (line != NULL)
1052 	    free (line);
1053 	free (repository);
1054     }
1055 
1056     if (strchr (dir, '/') == NULL)
1057     {
1058 	/* FIXME: chdir ("..") loses with symlinks.  */
1059 	/* Prune empty dirs on the way out - if necessary */
1060 	(void) CVS_CHDIR ("..");
1061 	if (update_prune_dirs && isemptydir (dir, 0))
1062 	{
1063 	    /* I'm not sure the existence_error is actually possible (except
1064 	       in cases where we really should print a message), but since
1065 	       this code used to ignore all errors, I'll play it safe.	*/
1066 	    if (unlink_file_dir (dir) < 0 && !existence_error (errno))
1067 		error (0, errno, "cannot remove %s directory", dir);
1068 	    Subdir_Deregister (entries, (char *) NULL, dir);
1069 	}
1070     }
1071 
1072     return (err);
1073 }
1074 
1075 static int isremoved PROTO ((Node *, void *));
1076 
1077 /* Returns 1 if the file indicated by node has been removed.  */
1078 static int
1079 isremoved (node, closure)
1080     Node *node;
1081     void *closure;
1082 {
1083     Entnode *entdata = (Entnode*) node->data;
1084 
1085     /* If the first character of the version is a '-', the file has been
1086        removed. */
1087     return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
1088 }
1089 
1090 /* Returns 1 if the argument directory is completely empty, other than the
1091    existence of the CVS directory entry.  Zero otherwise.  If MIGHT_NOT_EXIST
1092    and the directory doesn't exist, then just return 0.  */
1093 int
1094 isemptydir (dir, might_not_exist)
1095     char *dir;
1096     int might_not_exist;
1097 {
1098     DIR *dirp;
1099     struct dirent *dp;
1100 
1101     if ((dirp = CVS_OPENDIR (dir)) == NULL)
1102     {
1103 	if (might_not_exist && existence_error (errno))
1104 	    return 0;
1105 	error (0, errno, "cannot open directory %s for empty check", dir);
1106 	return (0);
1107     }
1108     errno = 0;
1109     while ((dp = readdir (dirp)) != NULL)
1110     {
1111 	if (strcmp (dp->d_name, ".") != 0
1112 	    && strcmp (dp->d_name, "..") != 0)
1113 	{
1114 	    if (strcmp (dp->d_name, CVSADM) != 0)
1115 	    {
1116 		/* An entry other than the CVS directory.  The directory
1117 		   is certainly not empty. */
1118 		(void) closedir (dirp);
1119 		return (0);
1120 	    }
1121 	    else
1122 	    {
1123 		/* The CVS directory entry.  We don't have to worry about
1124 		   this unless the Entries file indicates that files have
1125 		   been removed, but not committed, in this directory.
1126 		   (Removing the directory would prevent people from
1127 		   comitting the fact that they removed the files!) */
1128 		List *l;
1129 		int files_removed;
1130 		struct saved_cwd cwd;
1131 
1132 		if (save_cwd (&cwd))
1133 		    error_exit ();
1134 
1135 		if (CVS_CHDIR (dir) < 0)
1136 		    error (1, errno, "cannot change directory to %s", dir);
1137 		l = Entries_Open (0, NULL);
1138 		files_removed = walklist (l, isremoved, 0);
1139 		Entries_Close (l);
1140 
1141 		if (restore_cwd (&cwd, NULL))
1142 		    error_exit ();
1143 		free_cwd (&cwd);
1144 
1145 		if (files_removed != 0)
1146 		{
1147 		    /* There are files that have been removed, but not
1148 		       committed!  Do not consider the directory empty. */
1149 		    (void) closedir (dirp);
1150 		    return (0);
1151 		}
1152 	    }
1153 	}
1154 	errno = 0;
1155     }
1156     if (errno != 0)
1157     {
1158 	error (0, errno, "cannot read directory %s", dir);
1159 	(void) closedir (dirp);
1160 	return (0);
1161     }
1162     (void) closedir (dirp);
1163     return (1);
1164 }
1165 
1166 /*
1167  * scratch the Entries file entry associated with a file
1168  */
1169 static int
1170 scratch_file (finfo)
1171     struct file_info *finfo;
1172 {
1173     history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
1174     Scratch_Entry (finfo->entries, finfo->file);
1175     if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1176 	error (0, errno, "unable to remove %s", finfo->fullname);
1177     return (0);
1178 }
1179 
1180 /*
1181  * Check out a file.
1182  */
1183 static int
1184 checkout_file (finfo, vers_ts, adding, merging, update_server)
1185     struct file_info *finfo;
1186     Vers_TS *vers_ts;
1187     int adding;
1188     int merging;
1189     int update_server;
1190 {
1191     char *backup;
1192     int set_time, retval = 0;
1193     int status;
1194     int file_is_dead;
1195     struct buffer *revbuf;
1196 
1197     backup = NULL;
1198     revbuf = NULL;
1199 
1200     /* Don't screw with backup files if we're going to stdout, or if
1201        we are the server.  */
1202     if (!pipeout
1203 #ifdef SERVER_SUPPORT
1204 	&& ! server_active
1205 #endif
1206 	)
1207     {
1208 	backup = xmalloc (strlen (finfo->file)
1209 			  + sizeof (CVSADM)
1210 			  + sizeof (CVSPREFIX)
1211 			  + 10);
1212 	(void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1213 	if (isfile (finfo->file))
1214 	    rename_file (finfo->file, backup);
1215 	else
1216 	{
1217 	    /* If -f/-t wrappers are being used to wrap up a directory,
1218 	       then backup might be a directory instead of just a file.  */
1219 	    if (unlink_file_dir (backup) < 0)
1220 	    {
1221 		/* Not sure if the existence_error check is needed here.  */
1222 		if (!existence_error (errno))
1223 		    /* FIXME: should include update_dir in message.  */
1224 		    error (0, errno, "error removing %s", backup);
1225 	    }
1226 	    free (backup);
1227 	    backup = NULL;
1228 	}
1229     }
1230 
1231     file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
1232 
1233     if (!file_is_dead)
1234     {
1235 	/*
1236 	 * if we are checking out to stdout, print a nice message to
1237 	 * stderr, and add the -p flag to the command */
1238 	if (pipeout)
1239 	{
1240 	    if (!quiet)
1241 	    {
1242 		cvs_outerr ("\
1243 ===================================================================\n\
1244 Checking out ", 0);
1245 		cvs_outerr (finfo->fullname, 0);
1246 		cvs_outerr ("\n\
1247 RCS:  ", 0);
1248 		cvs_outerr (vers_ts->srcfile->path, 0);
1249 		cvs_outerr ("\n\
1250 VERS: ", 0);
1251 		cvs_outerr (vers_ts->vn_rcs, 0);
1252 		cvs_outerr ("\n***************\n", 0);
1253 	    }
1254 	}
1255 
1256 #ifdef SERVER_SUPPORT
1257 	if (update_server
1258 	    && server_active
1259 	    && ! pipeout
1260 	    && ! file_gzip_level
1261 	    && ! joining ()
1262 	    && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
1263 	{
1264 	    revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL);
1265 	    status = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1266 				   vers_ts->vn_rcs, vers_ts->vn_tag,
1267 				   vers_ts->options, RUN_TTY,
1268 				   checkout_to_buffer, revbuf);
1269 	}
1270 	else
1271 #endif
1272 	    status = RCS_checkout (vers_ts->srcfile,
1273 				   pipeout ? NULL : finfo->file,
1274 				   vers_ts->vn_rcs, vers_ts->vn_tag,
1275 				   vers_ts->options, RUN_TTY,
1276 				   (RCSCHECKOUTPROC) NULL, (void *) NULL);
1277     }
1278     if (file_is_dead || status == 0)
1279     {
1280 	mode_t mode;
1281 
1282 	mode = (mode_t) -1;
1283 
1284 	if (!pipeout)
1285 	{
1286 	    Vers_TS *xvers_ts;
1287 
1288 	    if (revbuf != NULL)
1289 	    {
1290 		struct stat sb;
1291 
1292 		/* FIXME: We should have RCS_checkout return the mode.  */
1293 		if (stat (vers_ts->srcfile->path, &sb) < 0)
1294 		    error (1, errno, "cannot stat %s",
1295 			   vers_ts->srcfile->path);
1296 		mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
1297 	    }
1298 
1299 	    if (cvswrite
1300 		&& !file_is_dead
1301 		&& !fileattr_get (finfo->file, "_watched"))
1302 	    {
1303 		if (revbuf == NULL)
1304 		    xchmod (finfo->file, 1);
1305 		else
1306 		{
1307 		    /* We know that we are the server here, so
1308                        although xchmod checks umask, we don't bother.  */
1309 		    mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
1310 			     | ((mode & S_IRGRP) ? S_IWGRP : 0)
1311 			     | ((mode & S_IROTH) ? S_IWOTH : 0));
1312 		}
1313 	    }
1314 
1315 	    {
1316 		/* A newly checked out file is never under the spell
1317 		   of "cvs edit".  If we think we were editing it
1318 		   from a previous life, clean up.  Would be better to
1319 		   check for same the working directory instead of
1320 		   same user, but that is hairy.  */
1321 
1322 		struct addremove_args args;
1323 
1324 		editor_set (finfo->file, getcaller (), NULL);
1325 
1326 		memset (&args, 0, sizeof args);
1327 		args.remove_temp = 1;
1328 		watch_modify_watchers (finfo->file, &args);
1329 	    }
1330 
1331 	    /* set the time from the RCS file iff it was unknown before */
1332 	    set_time =
1333 		(!noexec
1334 		 && (vers_ts->vn_user == NULL ||
1335 		     strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
1336 		 && !file_is_dead);
1337 
1338 	    wrap_fromcvs_process_file (finfo->file);
1339 
1340 	    xvers_ts = Version_TS (finfo, options, tag, date,
1341 				   force_tag_match, set_time);
1342 	    if (strcmp (xvers_ts->options, "-V4") == 0)
1343 		xvers_ts->options[0] = '\0';
1344 
1345 	    if (revbuf != NULL)
1346 	    {
1347 		/* If we stored the file data into a buffer, then we
1348                    didn't create a file at all, so xvers_ts->ts_user
1349                    is wrong.  The correct value is to have it be the
1350                    same as xvers_ts->ts_rcs, meaning that the working
1351                    file is unchanged from the RCS file.
1352 
1353 		   FIXME: We should tell Version_TS not to waste time
1354 		   statting the nonexistent file.
1355 
1356 		   FIXME: Actually, I don't think the ts_user value
1357 		   matters at all here.  The only use I know of is
1358 		   that it is printed in a trace message by
1359 		   Server_Register.  */
1360 
1361 		if (xvers_ts->ts_user != NULL)
1362 		    free (xvers_ts->ts_user);
1363 		xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
1364 	    }
1365 
1366 	    (void) time (&last_register_time);
1367 
1368 	    if (file_is_dead)
1369 	    {
1370 		if (xvers_ts->vn_user != NULL)
1371 		{
1372 		    error (0, 0,
1373 			   "warning: %s is not (any longer) pertinent",
1374  			   finfo->fullname);
1375 		}
1376 		Scratch_Entry (finfo->entries, finfo->file);
1377 #ifdef SERVER_SUPPORT
1378 		if (server_active && xvers_ts->ts_user == NULL)
1379 		    server_scratch_entry_only ();
1380 #endif
1381 		/* FIXME: Rather than always unlink'ing, and ignoring the
1382 		   existence_error, we should do the unlink only if
1383 		   vers_ts->ts_user is non-NULL.  Then there would be no
1384 		   need to ignore an existence_error (for example, if the
1385 		   user removes the file while we are running).  */
1386 		if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1387 		{
1388 		    error (0, errno, "cannot remove %s", finfo->fullname);
1389 		}
1390 	    }
1391 	    else
1392 		Register (finfo->entries, finfo->file,
1393 			  adding ? "0" : xvers_ts->vn_rcs,
1394 			  xvers_ts->ts_user, xvers_ts->options,
1395 			  xvers_ts->tag, xvers_ts->date,
1396 			  (char *)0); /* Clear conflict flag on fresh checkout */
1397 
1398 	    /* fix up the vers structure, in case it is used by join */
1399 	    if (join_rev1)
1400 	    {
1401 		if (vers_ts->vn_user != NULL)
1402 		    free (vers_ts->vn_user);
1403 		if (vers_ts->vn_rcs != NULL)
1404 		    free (vers_ts->vn_rcs);
1405 		vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1406 		vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1407 	    }
1408 
1409 	    /* If this is really Update and not Checkout, recode history */
1410 	    if (strcmp (command_name, "update") == 0)
1411 		history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1412 			       finfo->repository);
1413 
1414 	    freevers_ts (&xvers_ts);
1415 
1416 	    if (!really_quiet && !file_is_dead)
1417 	    {
1418 		write_letter (finfo, 'U');
1419 	    }
1420 	}
1421 
1422 #ifdef SERVER_SUPPORT
1423 	if (update_server && server_active)
1424 	    server_updated (finfo, vers_ts,
1425 			    merging ? SERVER_MERGED : SERVER_UPDATED,
1426 			    mode, (unsigned char *) NULL, revbuf);
1427 #endif
1428     }
1429     else
1430     {
1431 	if (backup != NULL)
1432 	{
1433 	    rename_file (backup, finfo->file);
1434 	    free (backup);
1435 	    backup = NULL;
1436 	}
1437 
1438 	error (0, 0, "could not check out %s", finfo->fullname);
1439 
1440 	retval = status;
1441     }
1442 
1443     if (backup != NULL)
1444     {
1445 	/* If -f/-t wrappers are being used to wrap up a directory,
1446 	   then backup might be a directory instead of just a file.  */
1447 	if (unlink_file_dir (backup) < 0)
1448 	{
1449 	    /* Not sure if the existence_error check is needed here.  */
1450 	    if (!existence_error (errno))
1451 		/* FIXME: should include update_dir in message.  */
1452 		error (0, errno, "error removing %s", backup);
1453 	}
1454 	free (backup);
1455     }
1456 
1457     return (retval);
1458 }
1459 
1460 #ifdef SERVER_SUPPORT
1461 
1462 /* This function is used to write data from a file being checked out
1463    into a buffer.  */
1464 
1465 static void
1466 checkout_to_buffer (callerdat, data, len)
1467      void *callerdat;
1468      const char *data;
1469      size_t len;
1470 {
1471     struct buffer *buf = (struct buffer *) callerdat;
1472 
1473     buf_output (buf, data, len);
1474 }
1475 
1476 #endif /* SERVER_SUPPORT */
1477 
1478 #ifdef SERVER_SUPPORT
1479 
1480 /* This structure is used to pass information between patch_file and
1481    patch_file_write.  */
1482 
1483 struct patch_file_data
1484 {
1485     /* File name, for error messages.  */
1486     const char *filename;
1487     /* File to which to write.  */
1488     FILE *fp;
1489     /* Whether to compute the MD5 checksum.  */
1490     int compute_checksum;
1491     /* Data structure for computing the MD5 checksum.  */
1492     struct MD5Context context;
1493     /* Set if the file has a final newline.  */
1494     int final_nl;
1495 };
1496 
1497 /* Patch a file.  Runs diff.  This is only done when running as the
1498  * server.  The hope is that the diff will be smaller than the file
1499  * itself.
1500  */
1501 static int
1502 patch_file (finfo, vers_ts, docheckout, file_info, checksum)
1503     struct file_info *finfo;
1504     Vers_TS *vers_ts;
1505     int *docheckout;
1506     struct stat *file_info;
1507     unsigned char *checksum;
1508 {
1509     char *backup;
1510     char *file1;
1511     char *file2;
1512     int retval = 0;
1513     int retcode = 0;
1514     int fail;
1515     long file_size;
1516     FILE *e;
1517     struct patch_file_data data;
1518 
1519     *docheckout = 0;
1520 
1521     if (noexec || pipeout || joining ())
1522     {
1523 	*docheckout = 1;
1524 	return 0;
1525     }
1526 
1527     /* If this file has been marked as being binary, then never send a
1528        patch.  */
1529     if (strcmp (vers_ts->options, "-kb") == 0)
1530     {
1531 	*docheckout = 1;
1532 	return 0;
1533     }
1534 
1535     /* First check that the first revision exists.  If it has been nuked
1536        by cvs admin -o, then just fall back to checking out entire
1537        revisions.  In some sense maybe we don't have to do this; after
1538        all cvs.texinfo says "Make sure that no-one has checked out a
1539        copy of the revision you outdate" but then again, that advice
1540        doesn't really make complete sense, because "cvs admin" operates
1541        on a working directory and so _someone_ will almost always have
1542        _some_ revision checked out.  */
1543     {
1544 	char *rev;
1545 
1546 	rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
1547 	if (rev == NULL)
1548 	{
1549 	    *docheckout = 1;
1550 	    return 0;
1551 	}
1552 	else
1553 	    free (rev);
1554     }
1555 
1556     /* If the revision is dead, let checkout_file handle it rather
1557        than duplicating the processing here.  */
1558     if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
1559     {
1560 	*docheckout = 1;
1561 	return 0;
1562     }
1563 
1564     backup = xmalloc (strlen (finfo->file)
1565 		      + sizeof (CVSADM)
1566 		      + sizeof (CVSPREFIX)
1567 		      + 10);
1568     (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1569     if (isfile (finfo->file))
1570         rename_file (finfo->file, backup);
1571     else
1572         (void) unlink_file (backup);
1573 
1574     file1 = xmalloc (strlen (finfo->file)
1575 		     + sizeof (CVSADM)
1576 		     + sizeof (CVSPREFIX)
1577 		     + 10);
1578     (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1579     file2 = xmalloc (strlen (finfo->file)
1580 		     + sizeof (CVSADM)
1581 		     + sizeof (CVSPREFIX)
1582 		     + 10);
1583     (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1584 
1585     fail = 0;
1586 
1587     /* We need to check out both revisions first, to see if either one
1588        has a trailing newline.  Because of this, we don't use rcsdiff,
1589        but just use diff.  */
1590 
1591     e = CVS_FOPEN (file1, "w");
1592     if (e == NULL)
1593 	error (1, errno, "cannot open %s", file1);
1594 
1595     data.filename = file1;
1596     data.fp = e;
1597     data.final_nl = 0;
1598     data.compute_checksum = 0;
1599 
1600     retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1601 			    vers_ts->vn_user, (char *) NULL,
1602 			    vers_ts->options, RUN_TTY,
1603 			    patch_file_write, (void *) &data);
1604 
1605     if (fclose (e) < 0)
1606 	error (1, errno, "cannot close %s", file1);
1607 
1608     if (retcode != 0 || ! data.final_nl)
1609 	fail = 1;
1610 
1611     if (! fail)
1612     {
1613 	e = CVS_FOPEN (file2, "w");
1614 	if (e == NULL)
1615 	    error (1, errno, "cannot open %s", file2);
1616 
1617 	data.filename = file2;
1618 	data.fp = e;
1619 	data.final_nl = 0;
1620 	data.compute_checksum = 1;
1621 	MD5Init (&data.context);
1622 
1623 	retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1624 				vers_ts->vn_rcs, (char *) NULL,
1625 				vers_ts->options, RUN_TTY,
1626 				patch_file_write, (void *) &data);
1627 
1628 	if (fclose (e) < 0)
1629 	    error (1, errno, "cannot close %s", file2);
1630 
1631 	if (retcode != 0 || ! data.final_nl)
1632 	    fail = 1;
1633 	else
1634 	    MD5Final (checksum, &data.context);
1635     }
1636 
1637     retcode = 0;
1638     if (! fail)
1639     {
1640 	char *diff_options;
1641 
1642 	/* FIXME: It might be better to come up with a diff library
1643            which can be shared with the diffutils.  */
1644 	/* If the client does not support the Rcs-diff command, we
1645            send a context diff, and the client must invoke patch.
1646            That approach was problematical for various reasons.  The
1647            new approach only requires running diff in the server; the
1648            client can handle everything without invoking an external
1649            program.  */
1650 	if (! rcs_diff_patches)
1651 	{
1652 	    /* We use -c, not -u, because we have no way of knowing
1653 	       which DIFF is in use.  */
1654 	    diff_options = "-c";
1655 	}
1656 	else
1657 	{
1658 	    /* Now that diff is librarified, we could be passing -a if
1659 	       we wanted to.  However, it is unclear to me whether we
1660 	       would want to.  Does diff -a, in any significant
1661 	       percentage of cases, produce patches which are smaller
1662 	       than the files it is patching?  I guess maybe text
1663 	       files with character sets which diff regards as
1664 	       'binary'.  Conversely, do they tend to be much larger
1665 	       in the bad cases?  This needs some more
1666 	       thought/investigation, I suspect.  */
1667 
1668 	    diff_options = "-n";
1669 	}
1670 	retcode = diff_exec (file1, file2, diff_options, finfo->file);
1671 
1672 	/* A retcode of 0 means no differences.  1 means some differences.  */
1673 	if (retcode != 0
1674 	    && retcode != 1)
1675 	{
1676 	    fail = 1;
1677 	}
1678 	else
1679 	{
1680 #define BINARY "Binary"
1681 	    char buf[sizeof BINARY];
1682 	    unsigned int c;
1683 
1684 	    /* Stat the original RCS file, and then adjust it the way
1685 	       that RCS_checkout would.  FIXME: This is an abstraction
1686 	       violation.  */
1687 	    if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0)
1688 		error (1, errno, "could not stat %s", vers_ts->srcfile->path);
1689 	    if (chmod (finfo->file,
1690 		       file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
1691 		< 0)
1692 		error (0, errno, "cannot change mode of file %s", finfo->file);
1693 	    if (cvswrite
1694 		&& !fileattr_get (finfo->file, "_watched"))
1695 		xchmod (finfo->file, 1);
1696 
1697 	    /* Check the diff output to make sure patch will be handle it.  */
1698 	    e = CVS_FOPEN (finfo->file, "r");
1699 	    if (e == NULL)
1700 		error (1, errno, "could not open diff output file %s",
1701 		       finfo->fullname);
1702 	    c = fread (buf, 1, sizeof BINARY - 1, e);
1703 	    buf[c] = '\0';
1704 	    if (strcmp (buf, BINARY) == 0)
1705 	    {
1706 		/* These are binary files.  We could use diff -a, but
1707 		   patch can't handle that.  */
1708 		fail = 1;
1709 	    }
1710 	    else {
1711 		/*
1712 		 * Don't send a diff if just sending the entire file
1713 		 * would be smaller
1714 		 */
1715 		fseek(e, 0L, SEEK_END);
1716 		if (file_size < ftell(e))
1717 		    fail = 1;
1718 	    }
1719 
1720 	    fclose (e);
1721 	}
1722     }
1723 
1724     if (! fail)
1725     {
1726         Vers_TS *xvers_ts;
1727 
1728         /* This stuff is just copied blindly from checkout_file.  I
1729 	   don't really know what it does.  */
1730         xvers_ts = Version_TS (finfo, options, tag, date,
1731 			       force_tag_match, 0);
1732 	if (strcmp (xvers_ts->options, "-V4") == 0)
1733 	    xvers_ts->options[0] = '\0';
1734 
1735 	Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1736 		  xvers_ts->ts_user, xvers_ts->options,
1737 		  xvers_ts->tag, xvers_ts->date, NULL);
1738 
1739 	if (CVS_STAT (finfo->file, file_info) < 0)
1740 	    error (1, errno, "could not stat %s", finfo->file);
1741 
1742 	/* If this is really Update and not Checkout, recode history */
1743 	if (strcmp (command_name, "update") == 0)
1744 	    history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1745 			   finfo->repository);
1746 
1747 	freevers_ts (&xvers_ts);
1748 
1749 	if (!really_quiet)
1750 	{
1751 	    write_letter (finfo, 'P');
1752 	}
1753     }
1754     else
1755     {
1756 	int old_errno = errno;		/* save errno value over the rename */
1757 
1758 	if (isfile (backup))
1759 	    rename_file (backup, finfo->file);
1760 
1761 	if (retcode != 0 && retcode != 1)
1762 	    error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1763 		   "could not diff %s", finfo->fullname);
1764 
1765 	*docheckout = 1;
1766 	retval = retcode;
1767     }
1768 
1769     (void) unlink_file (backup);
1770     (void) unlink_file (file1);
1771     (void) unlink_file (file2);
1772 
1773     free (backup);
1774     free (file1);
1775     free (file2);
1776     return (retval);
1777 }
1778 
1779 /* Write data to a file.  Record whether the last byte written was a
1780    newline.  Optionally compute a checksum.  This is called by
1781    patch_file via RCS_checkout.  */
1782 
1783 static void
1784 patch_file_write (callerdat, buffer, len)
1785      void *callerdat;
1786      const char *buffer;
1787      size_t len;
1788 {
1789     struct patch_file_data *data = (struct patch_file_data *) callerdat;
1790 
1791     if (fwrite (buffer, 1, len, data->fp) != len)
1792 	error (1, errno, "cannot write %s", data->filename);
1793 
1794     data->final_nl = (buffer[len - 1] == '\n');
1795 
1796     if (data->compute_checksum)
1797 	MD5Update (&data->context, (unsigned char *) buffer, len);
1798 }
1799 
1800 #endif /* SERVER_SUPPORT */
1801 
1802 /*
1803  * Several of the types we process only print a bit of information consisting
1804  * of a single letter and the name.
1805  */
1806 static void
1807 write_letter (finfo, letter)
1808     struct file_info *finfo;
1809     int letter;
1810 {
1811     if (!really_quiet)
1812     {
1813 	char *tag = NULL;
1814 	/* Big enough for "+updated" or any of its ilk.  */
1815 	char buf[80];
1816 
1817 	switch (letter)
1818 	{
1819 	    case 'U':
1820 		tag = "updated";
1821 		break;
1822 	    default:
1823 		/* We don't yet support tagged output except for "U".  */
1824 		break;
1825 	}
1826 
1827 	if (tag != NULL)
1828 	{
1829 	    sprintf (buf, "+%s", tag);
1830 	    cvs_output_tagged (buf, NULL);
1831 	}
1832 	buf[0] = letter;
1833 	buf[1] = ' ';
1834 	buf[2] = '\0';
1835 	cvs_output_tagged ("text", buf);
1836 	cvs_output_tagged ("fname", finfo->fullname);
1837 	cvs_output_tagged ("newline", NULL);
1838 	if (tag != NULL)
1839 	{
1840 	    sprintf (buf, "-%s", tag);
1841 	    cvs_output_tagged (buf, NULL);
1842 	}
1843     }
1844     return;
1845 }
1846 
1847 /*
1848  * Do all the magic associated with a file which needs to be merged
1849  */
1850 static int
1851 merge_file (finfo, vers)
1852     struct file_info *finfo;
1853     Vers_TS *vers;
1854 {
1855     char *backup;
1856     int status;
1857     int retcode = 0;
1858     int retval;
1859 
1860     /*
1861      * The users currently modified file is moved to a backup file name
1862      * ".#filename.version", so that it will stay around for a few days
1863      * before being automatically removed by some cron daemon.  The "version"
1864      * is the version of the file that the user was most up-to-date with
1865      * before the merge.
1866      */
1867     backup = xmalloc (strlen (finfo->file)
1868 		      + strlen (vers->vn_user)
1869 		      + sizeof (BAKPREFIX)
1870 		      + 10);
1871     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1872 
1873     (void) unlink_file (backup);
1874     copy_file (finfo->file, backup);
1875     xchmod (finfo->file, 1);
1876 
1877     if (strcmp (vers->options, "-kb") == 0
1878 	|| wrap_merge_is_copy (finfo->file)
1879 	|| special_file_mismatch (finfo, NULL, vers->vn_rcs))
1880     {
1881 	/* For binary files, a merge is always a conflict.  Same for
1882 	   files whose permissions or linkage do not match.  We give the
1883 	   user the two files, and let them resolve it.  It is possible
1884 	   that we should require a "touch foo" or similar step before
1885 	   we allow a checkin.  */
1886 
1887 	/* TODO: it may not always be necessary to regard a permission
1888 	   mismatch as a conflict.  The working file and the RCS file
1889 	   have a common ancestor `A'; if the working file's permissions
1890 	   match A's, then it's probably safe to overwrite them with the
1891 	   RCS permissions.  Only if the working file, the RCS file, and
1892 	   A all disagree should this be considered a conflict.  But more
1893 	   thought needs to go into this, and in the meantime it is safe
1894 	   to treat any such mismatch as an automatic conflict. -twp */
1895 
1896 #ifdef SERVER_SUPPORT
1897 	if (server_active)
1898 	    server_copy_file (finfo->file, finfo->update_dir,
1899 			      finfo->repository, backup);
1900 #endif
1901 
1902 	status = checkout_file (finfo, vers, 0, 1, 1);
1903 
1904 	/* Is there a better term than "nonmergeable file"?  What we
1905 	   really mean is, not something that CVS cannot or does not
1906 	   want to merge (there might be an external manual or
1907 	   automatic merge process).  */
1908 	error (0, 0, "nonmergeable file needs merge");
1909 	error (0, 0, "revision %s from repository is now in %s",
1910 	       vers->vn_rcs, finfo->fullname);
1911 	error (0, 0, "file from working directory is now in %s", backup);
1912 	write_letter (finfo, 'C');
1913 
1914 	history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
1915 		       finfo->repository);
1916 	retval = 0;
1917 	goto out;
1918     }
1919 
1920     status = RCS_merge(finfo->rcs, vers->srcfile->path, finfo->file,
1921 		       vers->options, vers->vn_user, vers->vn_rcs);
1922     if (status != 0 && status != 1)
1923     {
1924 	error (0, status == -1 ? errno : 0,
1925 	       "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
1926 	error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
1927 	       finfo->fullname, backup);
1928 	rename_file (backup, finfo->file);
1929 	retval = 1;
1930 	goto out;
1931     }
1932 
1933     if (strcmp (vers->options, "-V4") == 0)
1934 	vers->options[0] = '\0';
1935     (void) time (&last_register_time);
1936     {
1937 	char *cp = 0;
1938 
1939 	if (status)
1940 	    cp = time_stamp (finfo->file);
1941 	Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, vers->options,
1942 		  vers->tag, vers->date, cp);
1943 	if (cp)
1944 	    free (cp);
1945     }
1946 
1947     /* fix up the vers structure, in case it is used by join */
1948     if (join_rev1)
1949     {
1950 	if (vers->vn_user != NULL)
1951 	    free (vers->vn_user);
1952 	vers->vn_user = xstrdup (vers->vn_rcs);
1953     }
1954 
1955 #ifdef SERVER_SUPPORT
1956     /* Send the new contents of the file before the message.  If we
1957        wanted to be totally correct, we would have the client write
1958        the message only after the file has safely been written.  */
1959     if (server_active)
1960     {
1961         server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
1962 			  backup);
1963 	server_updated (finfo, vers, SERVER_MERGED,
1964 			(mode_t) -1, (unsigned char *) NULL,
1965 			(struct buffer *) NULL);
1966     }
1967 #endif
1968 
1969     if (!noexec && !xcmp (backup, finfo->file))
1970     {
1971 	printf ("%s already contains the differences between %s and %s\n",
1972 		finfo->fullname, vers->vn_user, vers->vn_rcs);
1973 	history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
1974 		       finfo->repository);
1975 	retval = 0;
1976 	goto out;
1977     }
1978 
1979     if (status == 1)
1980     {
1981 	if (!noexec)
1982 	    error (0, 0, "conflicts found in %s", finfo->fullname);
1983 
1984 	write_letter (finfo, 'C');
1985 
1986 	history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
1987 
1988     }
1989     else if (retcode == -1)
1990     {
1991 	error (1, errno, "fork failed while examining update of %s",
1992 	       finfo->fullname);
1993     }
1994     else
1995     {
1996 	write_letter (finfo, 'M');
1997 	history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
1998 		       finfo->repository);
1999     }
2000     retval = 0;
2001  out:
2002     free (backup);
2003     return retval;
2004 }
2005 
2006 /*
2007  * Do all the magic associated with a file which needs to be joined
2008  * (-j option)
2009  */
2010 static void
2011 join_file (finfo, vers)
2012     struct file_info *finfo;
2013     Vers_TS *vers;
2014 {
2015     char *backup;
2016     char *options;
2017     int status;
2018 
2019     char *rev1;
2020     char *rev2;
2021     char *jrev1;
2022     char *jrev2;
2023     char *jdate1;
2024     char *jdate2;
2025 
2026     jrev1 = join_rev1;
2027     jrev2 = join_rev2;
2028     jdate1 = date_rev1;
2029     jdate2 = date_rev2;
2030 
2031     /* Determine if we need to do anything at all.  */
2032     if (vers->srcfile == NULL ||
2033 	vers->srcfile->path == NULL)
2034     {
2035 	return;
2036     }
2037 
2038     /* If only one join revision is specified, it becomes the second
2039        revision.  */
2040     if (jrev2 == NULL)
2041     {
2042 	jrev2 = jrev1;
2043 	jrev1 = NULL;
2044 	jdate2 = jdate1;
2045 	jdate1 = NULL;
2046     }
2047 
2048     /* Convert the second revision, walking branches and dates.  */
2049     rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
2050 
2051     /* If this is a merge of two revisions, get the first revision.
2052        If only one join tag was specified, then the first revision is
2053        the greatest common ancestor of the second revision and the
2054        working file.  */
2055     if (jrev1 != NULL)
2056 	rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL);
2057     else
2058     {
2059 	/* Note that we use vn_rcs here, since vn_user may contain a
2060            special string such as "-nn".  */
2061 	if (vers->vn_rcs == NULL)
2062 	    rev1 = NULL;
2063 	else if (rev2 == NULL)
2064 	{
2065 	    /* This means that the file never existed on the branch.
2066                It does not mean that the file was removed on the
2067                branch: that case is represented by a dead rev2.  If
2068                the file never existed on the branch, then we have
2069                nothing to merge, so we just return.  */
2070 	    return;
2071 	}
2072 	else
2073 	    rev1 = gca (vers->vn_rcs, rev2);
2074     }
2075 
2076     /* Handle a nonexistent or dead merge target.  */
2077     if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
2078     {
2079 	char *mrev;
2080 
2081 	if (rev2 != NULL)
2082 	    free (rev2);
2083 
2084 	/* If the first revision doesn't exist either, then there is
2085            no change between the two revisions, so we don't do
2086            anything.  */
2087 	if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2088 	{
2089 	    if (rev1 != NULL)
2090 		free (rev1);
2091 	    return;
2092 	}
2093 
2094 	/* If we are merging two revisions, then the file was removed
2095 	   between the first revision and the second one.  In this
2096 	   case we want to mark the file for removal.
2097 
2098 	   If we are merging one revision, then the file has been
2099 	   removed between the greatest common ancestor and the merge
2100 	   revision.  From the perspective of the branch on to which
2101 	   we ar emerging, which may be the trunk, either 1) the file
2102 	   does not currently exist on the target, or 2) the file has
2103 	   not been modified on the target branch since the greatest
2104 	   common ancestor, or 3) the file has been modified on the
2105 	   target branch since the greatest common ancestor.  In case
2106 	   1 there is nothing to do.  In case 2 we mark the file for
2107 	   removal.  In case 3 we have a conflict.
2108 
2109 	   Note that the handling is slightly different depending upon
2110 	   whether one or two join targets were specified.  If two
2111 	   join targets were specified, we don't check whether the
2112 	   file was modified since a given point.  My reasoning is
2113 	   that if you ask for an explicit merge between two tags,
2114 	   then you want to merge in whatever was changed between
2115 	   those two tags.  If a file was removed between the two
2116 	   tags, then you want it to be removed.  However, if you ask
2117 	   for a merge of a branch, then you want to merge in all
2118 	   changes which were made on the branch.  If a file was
2119 	   removed on the branch, that is a change to the file.  If
2120 	   the file was also changed on the main line, then that is
2121 	   also a change.  These two changes--the file removal and the
2122 	   modification--must be merged.  This is a conflict.  */
2123 
2124 	/* If the user file is dead, or does not exist, or has been
2125            marked for removal, then there is nothing to do.  */
2126 	if (vers->vn_user == NULL
2127 	    || vers->vn_user[0] == '-'
2128 	    || RCS_isdead (vers->srcfile, vers->vn_user))
2129 	{
2130 	    if (rev1 != NULL)
2131 		free (rev1);
2132 	    return;
2133 	}
2134 
2135 	/* If the user file has been marked for addition, or has been
2136 	   locally modified, then we have a conflict which we can not
2137 	   resolve.  No_Difference will already have been called in
2138 	   this case, so comparing the timestamps is sufficient to
2139 	   determine whether the file is locally modified.  */
2140 	if (strcmp (vers->vn_user, "0") == 0
2141 	    || (vers->ts_user != NULL
2142 		&& strcmp (vers->ts_user, vers->ts_rcs) != 0))
2143 	{
2144 	    if (jdate2 != NULL)
2145 		error (0, 0,
2146 		       "file %s is locally modified, but has been removed in revision %s as of %s",
2147 		       finfo->fullname, jrev2, jdate2);
2148 	    else
2149 		error (0, 0,
2150 		       "file %s is locally modified, but has been removed in revision %s",
2151 		       finfo->fullname, jrev2);
2152 
2153 	    /* FIXME: Should we arrange to return a non-zero exit
2154                status?  */
2155 
2156 	    if (rev1 != NULL)
2157 		free (rev1);
2158 
2159 	    return;
2160 	}
2161 
2162 	/* If only one join tag was specified, and the user file has
2163            been changed since the greatest common ancestor (rev1),
2164            then there is a conflict we can not resolve.  See above for
2165            the rationale.  */
2166 	if (join_rev2 == NULL
2167 	    && strcmp (rev1, vers->vn_user) != 0)
2168 	{
2169 	    if (jdate2 != NULL)
2170 		error (0, 0,
2171 		       "file %s has been modified, but has been removed in revision %s as of %s",
2172 		       finfo->fullname, jrev2, jdate2);
2173 	    else
2174 		error (0, 0,
2175 		       "file %s has been modified, but has been removed in revision %s",
2176 		       finfo->fullname, jrev2);
2177 
2178 	    /* FIXME: Should we arrange to return a non-zero exit
2179                status?  */
2180 
2181 	    if (rev1 != NULL)
2182 		free (rev1);
2183 
2184 	    return;
2185 	}
2186 
2187 	if (rev1 != NULL)
2188 	    free (rev1);
2189 
2190 	/* The user file exists and has not been modified.  Mark it
2191            for removal.  FIXME: If we are doing a checkout, this has
2192            the effect of first checking out the file, and then
2193            removing it.  It would be better to just register the
2194            removal.  */
2195 #ifdef SERVER_SUPPORT
2196 	if (server_active)
2197 	{
2198 	    server_scratch (finfo->file);
2199 	    server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
2200 			    (unsigned char *) NULL, (struct buffer *) NULL);
2201 	}
2202 #endif
2203 	mrev = xmalloc (strlen (vers->vn_user) + 2);
2204 	sprintf (mrev, "-%s", vers->vn_user);
2205 	Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
2206 		  vers->options, vers->tag, vers->date, vers->ts_conflict);
2207 	free (mrev);
2208 	/* We need to check existence_error here because if we are
2209            running as the server, and the file is up to date in the
2210            working directory, the client will not have sent us a copy.  */
2211 	if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
2212 	    error (0, errno, "cannot remove file %s", finfo->fullname);
2213 #ifdef SERVER_SUPPORT
2214 	if (server_active)
2215 	    server_checked_in (finfo->file, finfo->update_dir,
2216 			       finfo->repository);
2217 #endif
2218 	if (! really_quiet)
2219 	    error (0, 0, "scheduling %s for removal", finfo->fullname);
2220 
2221 	return;
2222     }
2223 
2224     /* If the target of the merge is the same as the working file
2225        revision, then there is nothing to do.  */
2226     if (vers->vn_user != NULL && strcmp (rev2, vers->vn_user) == 0)
2227     {
2228 	if (rev1 != NULL)
2229 	    free (rev1);
2230 	free (rev2);
2231 	return;
2232     }
2233 
2234     /* If rev1 is dead or does not exist, then the file was added
2235        between rev1 and rev2.  */
2236     if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2237     {
2238 	if (rev1 != NULL)
2239 	    free (rev1);
2240 	free (rev2);
2241 
2242 	/* If the file does not exist in the working directory, then
2243            we can just check out the new revision and mark it for
2244            addition.  */
2245 	if (vers->vn_user == NULL)
2246 	{
2247 	    Vers_TS *xvers;
2248 
2249 	    xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
2250 
2251 	    /* FIXME: If checkout_file fails, we should arrange to
2252                return a non-zero exit status.  */
2253 	    status = checkout_file (finfo, xvers, 1, 0, 1);
2254 
2255 	    freevers_ts (&xvers);
2256 
2257 	    return;
2258 	}
2259 
2260 	/* The file currently exists in the working directory, so we
2261            have a conflict which we can not resolve.  Note that this
2262            is true even if the file is marked for addition or removal.  */
2263 
2264 	if (jdate2 != NULL)
2265 	    error (0, 0,
2266 		   "file %s exists, but has been added in revision %s as of %s",
2267 		   finfo->fullname, jrev2, jdate2);
2268 	else
2269 	    error (0, 0,
2270 		   "file %s exists, but has been added in revision %s",
2271 		   finfo->fullname, jrev2);
2272 
2273 	return;
2274     }
2275 
2276     /* If the two merge revisions are the same, then there is nothing
2277        to do.  */
2278     if (strcmp (rev1, rev2) == 0)
2279     {
2280 	free (rev1);
2281 	free (rev2);
2282 	return;
2283     }
2284 
2285     /* If there is no working file, then we can't do the merge.  */
2286     if (vers->vn_user == NULL)
2287     {
2288 	free (rev1);
2289 	free (rev2);
2290 
2291 	if (jdate2 != NULL)
2292 	    error (0, 0,
2293 		   "file %s is present in revision %s as of %s",
2294 		   finfo->fullname, jrev2, jdate2);
2295 	else
2296 	    error (0, 0,
2297 		   "file %s is present in revision %s",
2298 		   finfo->fullname, jrev2);
2299 
2300 	/* FIXME: Should we arrange to return a non-zero exit status?  */
2301 
2302 	return;
2303     }
2304 
2305 #ifdef SERVER_SUPPORT
2306     if (server_active && !isreadable (finfo->file))
2307     {
2308 	int retcode;
2309 	/* The file is up to date.  Need to check out the current contents.  */
2310 	retcode = RCS_checkout (vers->srcfile, finfo->file,
2311 				vers->vn_user, (char *) NULL,
2312 				(char *) NULL, RUN_TTY,
2313 				(RCSCHECKOUTPROC) NULL, (void *) NULL);
2314 	if (retcode != 0)
2315 	    error (1, 0,
2316 		   "failed to check out %s file", finfo->fullname);
2317     }
2318 #endif
2319 
2320     /*
2321      * The users currently modified file is moved to a backup file name
2322      * ".#filename.version", so that it will stay around for a few days
2323      * before being automatically removed by some cron daemon.  The "version"
2324      * is the version of the file that the user was most up-to-date with
2325      * before the merge.
2326      */
2327     backup = xmalloc (strlen (finfo->file)
2328 		      + strlen (vers->vn_user)
2329 		      + sizeof (BAKPREFIX)
2330 		      + 10);
2331     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
2332 
2333     (void) unlink_file (backup);
2334     copy_file (finfo->file, backup);
2335     xchmod (finfo->file, 1);
2336 
2337     options = vers->options;
2338 #if 0
2339     if (*options == '\0')
2340 	options = "-kk";		/* to ignore keyword expansions */
2341 #endif
2342 
2343     /* If the source of the merge is the same as the working file
2344        revision, then we can just RCS_checkout the target (no merging
2345        as such).  In the text file case, this is probably quite
2346        similar to the RCS_merge, but in the binary file case,
2347        RCS_merge gives all kinds of trouble.  */
2348     if (vers->vn_user != NULL
2349 	&& strcmp (rev1, vers->vn_user) == 0
2350 	/* See comments above about how No_Difference has already been
2351 	   called.  */
2352 	&& vers->ts_user != NULL
2353 	&& strcmp (vers->ts_user, vers->ts_rcs) == 0
2354 
2355 	/* This is because of the worry below about $Name.  If that
2356 	   isn't a problem, I suspect this code probably works for
2357 	   text files too.  */
2358 	&& (strcmp (options, "-kb") == 0
2359 	    || wrap_merge_is_copy (finfo->file)))
2360     {
2361 	/* FIXME: what about nametag?  What does RCS_merge do with
2362 	   $Name?  */
2363 	if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
2364 			  RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
2365 	    status = 2;
2366 	else
2367 	    status = 0;
2368 
2369 	/* OK, this is really stupid.  RCS_checkout carefully removes
2370 	   write permissions, and we carefully put them back.  But
2371 	   until someone gets around to fixing it, that seems like the
2372 	   easiest way to get what would seem to be the right mode.
2373 	   I don't check CVSWRITE or _watched; I haven't thought about
2374 	   that in great detail, but it seems like a watched file should
2375 	   be checked out (writable) after a merge.  */
2376 	xchmod (finfo->file, 1);
2377 
2378 	/* Traditionally, the text file case prints a whole bunch of
2379 	   scary looking and verbose output which fails to tell the user
2380 	   what is really going on (it gives them rev1 and rev2 but doesn't
2381 	   indicate in any way that rev1 == vn_user).  I think just a
2382 	   simple "U foo" is good here; it seems analogous to the case in
2383 	   which the file was added on the branch in terms of what to
2384 	   print.  */
2385 	write_letter (finfo, 'U');
2386     }
2387     else if (strcmp (options, "-kb") == 0
2388 	     || wrap_merge_is_copy (finfo->file)
2389 	     || special_file_mismatch (finfo, rev1, rev2))
2390     {
2391 	/* We are dealing with binary files, or files with a
2392 	   permission/linkage mismatch, and real merging would
2393 	   need to take place.  This is a conflict.  We give the user
2394 	   the two files, and let them resolve it.  It is possible
2395 	   that we should require a "touch foo" or similar step before
2396 	   we allow a checkin.  */
2397 	if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
2398 			  RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
2399 	    status = 2;
2400 	else
2401 	    status = 0;
2402 
2403 	/* OK, this is really stupid.  RCS_checkout carefully removes
2404 	   write permissions, and we carefully put them back.  But
2405 	   until someone gets around to fixing it, that seems like the
2406 	   easiest way to get what would seem to be the right mode.
2407 	   I don't check CVSWRITE or _watched; I haven't thought about
2408 	   that in great detail, but it seems like a watched file should
2409 	   be checked out (writable) after a merge.  */
2410 	xchmod (finfo->file, 1);
2411 
2412 	/* Hmm.  We don't give them REV1 anywhere.  I guess most people
2413 	   probably don't have a 3-way merge tool for the file type in
2414 	   question, and might just get confused if we tried to either
2415 	   provide them with a copy of the file from REV1, or even just
2416 	   told them what REV1 is so they can get it themself, but it
2417 	   might be worth thinking about.  */
2418 	/* See comment in merge_file about the "nonmergeable file"
2419 	   terminology.  */
2420 	error (0, 0, "nonmergeable file needs merge");
2421 	error (0, 0, "revision %s from repository is now in %s",
2422 	       rev2, finfo->fullname);
2423 	error (0, 0, "file from working directory is now in %s", backup);
2424 	write_letter (finfo, 'C');
2425     }
2426     else
2427 	status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2428 			    options, rev1, rev2);
2429 
2430     if (status != 0 && status != 1)
2431     {
2432 	error (0, status == -1 ? errno : 0,
2433 	       "could not merge revision %s of %s", rev2, finfo->fullname);
2434 	error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2435 	       finfo->fullname, backup);
2436 	rename_file (backup, finfo->file);
2437     }
2438     free (rev1);
2439     free (rev2);
2440 
2441 #ifdef SERVER_SUPPORT
2442     /*
2443      * If we're in server mode, then we need to re-register the file
2444      * even if there were no conflicts (status == 0).
2445      * This tells server_updated() to send the modified file back to
2446      * the client.
2447      */
2448     if (status == 1 || (status == 0 && server_active))
2449 #else
2450     if (status == 1)
2451 #endif
2452     {
2453 	char *cp = 0;
2454 
2455 	if (status)
2456 	    cp = time_stamp (finfo->file);
2457 	Register (finfo->entries, finfo->file,
2458 		  vers->vn_rcs, vers->ts_rcs, vers->options,
2459 		  vers->tag, vers->date, cp);
2460 	if (cp)
2461 	    free(cp);
2462     }
2463 
2464 #ifdef SERVER_SUPPORT
2465     if (server_active)
2466     {
2467 	server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
2468 			  backup);
2469 	server_updated (finfo, vers, SERVER_MERGED,
2470 			(mode_t) -1, (unsigned char *) NULL,
2471 			(struct buffer *) NULL);
2472     }
2473 #endif
2474     free (backup);
2475 }
2476 
2477 /*
2478  * Report whether revisions REV1 and REV2 of FINFO agree on:
2479  *   . file ownership
2480  *   . permissions
2481  *   . major and minor device numbers
2482  *   . symbolic links
2483  *   . hard links
2484  *
2485  * If either REV1 or REV2 is NULL, the working copy is used instead.
2486  *
2487  * Return 1 if the files differ on these data.
2488  */
2489 
2490 int
2491 special_file_mismatch (finfo, rev1, rev2)
2492     struct file_info *finfo;
2493     char *rev1;
2494     char *rev2;
2495 {
2496 #ifdef PRESERVE_PERMISSIONS_SUPPORT
2497     struct stat sb;
2498     RCSVers *vp;
2499     Node *n;
2500     uid_t rev1_uid, rev2_uid;
2501     gid_t rev1_gid, rev2_gid;
2502     mode_t rev1_mode, rev2_mode;
2503     unsigned long dev_long;
2504     dev_t rev1_dev, rev2_dev;
2505     char *rev1_symlink = NULL;
2506     char *rev2_symlink = NULL;
2507     List *rev1_hardlinks;
2508     List *rev2_hardlinks;
2509     int check_uids, check_gids, check_modes;
2510     int result;
2511 
2512     /* If we don't care about special file info, then
2513        don't report a mismatch in any case. */
2514     if (!preserve_perms)
2515 	return 0;
2516 
2517     /* When special_file_mismatch is called from No_Difference, the
2518        RCS file has been only partially parsed.  We must read the
2519        delta tree in order to compare special file info recorded in
2520        the delta nodes.  (I think this is safe. -twp) */
2521     if (finfo->rcs->flags & PARTIAL)
2522 	RCS_reparsercsfile (finfo->rcs, NULL, NULL);
2523 
2524     check_uids = check_gids = check_modes = 1;
2525 
2526     /* Obtain file information for REV1.  If this is null, then stat
2527        finfo->file and use that info. */
2528     /* If a revision does not know anything about its status,
2529        then presumably it doesn't matter, and indicates no conflict. */
2530 
2531     if (rev1 == NULL)
2532     {
2533 	if (islink (finfo->file))
2534 	    rev1_symlink = xreadlink (finfo->file);
2535 	else
2536 	{
2537 	    if (CVS_LSTAT (finfo->file, &sb) < 0)
2538 		error (1, errno, "could not get file information for %s",
2539 		       finfo->file);
2540 	    rev1_uid = sb.st_uid;
2541 	    rev1_gid = sb.st_gid;
2542 	    rev1_mode = sb.st_mode;
2543 	    if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
2544 		rev1_dev = sb.st_rdev;
2545 	}
2546 	rev1_hardlinks = list_linked_files_on_disk (finfo->file);
2547     }
2548     else
2549     {
2550 	n = findnode (finfo->rcs->versions, rev1);
2551 	vp = (RCSVers *) n->data;
2552 
2553 	n = findnode (vp->other_delta, "symlink");
2554 	if (n != NULL)
2555 	    rev1_symlink = xstrdup (n->data);
2556 	else
2557 	{
2558 	    n = findnode (vp->other_delta, "owner");
2559 	    if (n == NULL)
2560 		check_uids = 0;	/* don't care */
2561 	    else
2562 		rev1_uid = strtoul (n->data, NULL, 10);
2563 
2564 	    n = findnode (vp->other_delta, "group");
2565 	    if (n == NULL)
2566 		check_gids = 0;	/* don't care */
2567 	    else
2568 		rev1_gid = strtoul (n->data, NULL, 10);
2569 
2570 	    n = findnode (vp->other_delta, "permissions");
2571 	    if (n == NULL)
2572 		check_modes = 0;	/* don't care */
2573 	    else
2574 		rev1_mode = strtoul (n->data, NULL, 8);
2575 
2576 	    n = findnode (vp->other_delta, "special");
2577 	    if (n == NULL)
2578 		rev1_mode |= S_IFREG;
2579 	    else
2580 	    {
2581 		/* If the size of `ftype' changes, fix the sscanf call also */
2582 		char ftype[16+1];
2583 		if (sscanf (n->data, "%16s %lu", ftype,
2584 			    &dev_long) < 2)
2585 		    error (1, 0, "%s:%s has bad `special' newphrase %s",
2586 			   finfo->file, rev1, n->data);
2587 		rev1_dev = dev_long;
2588 		if (strcmp (ftype, "character") == 0)
2589 		    rev1_mode |= S_IFCHR;
2590 		else if (strcmp (ftype, "block") == 0)
2591 		    rev1_mode |= S_IFBLK;
2592 		else
2593 		    error (0, 0, "%s:%s unknown file type `%s'",
2594 			   finfo->file, rev1, ftype);
2595 	    }
2596 
2597 	    rev1_hardlinks = vp->hardlinks;
2598 	    if (rev1_hardlinks == NULL)
2599 		rev1_hardlinks = getlist();
2600 	}
2601     }
2602 
2603     /* Obtain file information for REV2. */
2604     if (rev2 == NULL)
2605     {
2606 	if (islink (finfo->file))
2607 	    rev2_symlink = xreadlink (finfo->file);
2608 	else
2609 	{
2610 	    if (CVS_LSTAT (finfo->file, &sb) < 0)
2611 		error (1, errno, "could not get file information for %s",
2612 		       finfo->file);
2613 	    rev2_uid = sb.st_uid;
2614 	    rev2_gid = sb.st_gid;
2615 	    rev2_mode = sb.st_mode;
2616 	    if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
2617 		rev2_dev = sb.st_rdev;
2618 	}
2619 	rev2_hardlinks = list_linked_files_on_disk (finfo->file);
2620     }
2621     else
2622     {
2623 	n = findnode (finfo->rcs->versions, rev2);
2624 	vp = (RCSVers *) n->data;
2625 
2626 	n = findnode (vp->other_delta, "symlink");
2627 	if (n != NULL)
2628 	    rev2_symlink = xstrdup (n->data);
2629 	else
2630 	{
2631 	    n = findnode (vp->other_delta, "owner");
2632 	    if (n == NULL)
2633 		check_uids = 0;	/* don't care */
2634 	    else
2635 		rev2_uid = strtoul (n->data, NULL, 10);
2636 
2637 	    n = findnode (vp->other_delta, "group");
2638 	    if (n == NULL)
2639 		check_gids = 0;	/* don't care */
2640 	    else
2641 		rev2_gid = strtoul (n->data, NULL, 10);
2642 
2643 	    n = findnode (vp->other_delta, "permissions");
2644 	    if (n == NULL)
2645 		check_modes = 0;	/* don't care */
2646 	    else
2647 		rev2_mode = strtoul (n->data, NULL, 8);
2648 
2649 	    n = findnode (vp->other_delta, "special");
2650 	    if (n == NULL)
2651 		rev2_mode |= S_IFREG;
2652 	    else
2653 	    {
2654 		/* If the size of `ftype' changes, fix the sscanf call also */
2655 		char ftype[16+1];
2656 		if (sscanf (n->data, "%16s %lu", ftype,
2657 			    &dev_long) < 2)
2658 		    error (1, 0, "%s:%s has bad `special' newphrase %s",
2659 			   finfo->file, rev2, n->data);
2660 		rev2_dev = dev_long;
2661 		if (strcmp (ftype, "character") == 0)
2662 		    rev2_mode |= S_IFCHR;
2663 		else if (strcmp (ftype, "block") == 0)
2664 		    rev2_mode |= S_IFBLK;
2665 		else
2666 		    error (0, 0, "%s:%s unknown file type `%s'",
2667 			   finfo->file, rev2, ftype);
2668 	    }
2669 
2670 	    rev2_hardlinks = vp->hardlinks;
2671 	    if (rev2_hardlinks == NULL)
2672 		rev2_hardlinks = getlist();
2673 	}
2674     }
2675 
2676     /* Check the user/group ownerships and file permissions, printing
2677        an error for each mismatch found.  Return 0 if all characteristics
2678        matched, and 1 otherwise. */
2679 
2680     result = 0;
2681 
2682     /* Compare symlinks first, since symlinks are simpler (don't have
2683        any other characteristics). */
2684     if (rev1_symlink != NULL && rev2_symlink == NULL)
2685     {
2686 	error (0, 0, "%s is a symbolic link",
2687 	       (rev1 == NULL ? "working file" : rev1));
2688 	result = 1;
2689     }
2690     else if (rev1_symlink == NULL && rev2_symlink != NULL)
2691     {
2692 	error (0, 0, "%s is a symbolic link",
2693 	       (rev2 == NULL ? "working file" : rev2));
2694 	result = 1;
2695     }
2696     else if (rev1_symlink != NULL)
2697 	result = (strcmp (rev1_symlink, rev2_symlink) == 0);
2698     else
2699     {
2700 	/* Compare user ownership. */
2701 	if (check_uids && rev1_uid != rev2_uid)
2702 	{
2703 	    error (0, 0, "%s: owner mismatch between %s and %s",
2704 		   finfo->file,
2705 		   (rev1 == NULL ? "working file" : rev1),
2706 		   (rev2 == NULL ? "working file" : rev2));
2707 	    result = 1;
2708 	}
2709 
2710 	/* Compare group ownership. */
2711 	if (check_gids && rev1_gid != rev2_gid)
2712 	{
2713 	    error (0, 0, "%s: group mismatch between %s and %s",
2714 		   finfo->file,
2715 		   (rev1 == NULL ? "working file" : rev1),
2716 		   (rev2 == NULL ? "working file" : rev2));
2717 	    result = 1;
2718 	}
2719 
2720 	/* Compare permissions. */
2721 	if (check_modes &&
2722 	    (rev1_mode & 07777) != (rev2_mode & 07777))
2723 	{
2724 	    error (0, 0, "%s: permission mismatch between %s and %s",
2725 		   finfo->file,
2726 		   (rev1 == NULL ? "working file" : rev1),
2727 		   (rev2 == NULL ? "working file" : rev2));
2728 	    result = 1;
2729 	}
2730 
2731 	/* Compare device file characteristics. */
2732 	if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
2733 	{
2734 	    error (0, 0, "%s: %s and %s are different file types",
2735 		   finfo->file,
2736 		   (rev1 == NULL ? "working file" : rev1),
2737 		   (rev2 == NULL ? "working file" : rev2));
2738 	    result = 1;
2739 	}
2740 	else if (S_ISBLK (rev1_mode))
2741 	{
2742 	    if (rev1_dev != rev2_dev)
2743 	    {
2744 		error (0, 0, "%s: device numbers of %s and %s do not match",
2745 		       finfo->file,
2746 		       (rev1 == NULL ? "working file" : rev1),
2747 		       (rev2 == NULL ? "working file" : rev2));
2748 		result = 1;
2749 	    }
2750 	}
2751 
2752 	/* Compare hard links. */
2753 	if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
2754 	{
2755 	    error (0, 0, "%s: hard linkage of %s and %s do not match",
2756 		   finfo->file,
2757 		   (rev1 == NULL ? "working file" : rev1),
2758 		   (rev2 == NULL ? "working file" : rev2));
2759 	    result = 1;
2760 	}
2761     }
2762 
2763     if (rev1_symlink != NULL)
2764 	free (rev1_symlink);
2765     if (rev2_symlink != NULL)
2766 	free (rev2_symlink);
2767     if (rev1_hardlinks != NULL)
2768 	dellist (&rev1_hardlinks);
2769     if (rev2_hardlinks != NULL)
2770 	dellist (&rev2_hardlinks);
2771 
2772     return result;
2773 #else
2774     return 0;
2775 #endif
2776 }
2777 
2778 int
2779 joining ()
2780 {
2781     return (join_rev1 != NULL);
2782 }
2783