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