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