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