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