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