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