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