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