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