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