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