xref: /openbsd-src/gnu/usr.bin/cvs/src/update.c (revision 7e4d5a85f91e22adbbb2241021e71287d24b0996)
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  *
5  * You may distribute under the terms of the GNU General Public License as
6  * specified in the README file that comes with the CVS 1.4 kit.
7  *
8  * "update" updates the version in the present directory with respect to the RCS
9  * repository.  The present version must have been created by "checkout". The
10  * user can keep up-to-date by calling "update" whenever he feels like it.
11  *
12  * The present version can be committed by "commit", but this keeps the version
13  * in tact.
14  *
15  * Arguments following the options are taken to be file names to be updated,
16  * rather than updating the entire directory.
17  *
18  * Modified or non-existent RCS files are checked out and reported as U
19  * <user_file>
20  *
21  * Modified user files are reported as M <user_file>.  If both the RCS file and
22  * the user file have been modified, the user file is replaced by the result
23  * of rcsmerge, and a backup file is written for the user in .#file.version.
24  * If this throws up irreconcilable differences, the file is reported as C
25  * <user_file>, and as M <user_file> otherwise.
26  *
27  * Files added but not yet committed are reported as A <user_file>. Files
28  * removed but not yet committed are reported as R <user_file>.
29  *
30  * If the current directory contains subdirectories that hold concurrent
31  * versions, these are updated too.  If the -d option was specified, new
32  * directories added to the repository are automatically created and updated
33  * as well.
34  */
35 
36 #include "cvs.h"
37 #ifdef SERVER_SUPPORT
38 #include "md5.h"
39 #endif
40 #include "watch.h"
41 #include "fileattr.h"
42 #include "edit.h"
43 
44 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
45 				 int adding));
46 #ifdef SERVER_SUPPORT
47 static int patch_file PROTO ((struct file_info *finfo,
48 			      Vers_TS *vers_ts,
49 			      int *docheckout, struct stat *file_info,
50 			      unsigned char *checksum));
51 #endif
52 static int isemptydir PROTO((char *dir));
53 static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
54 static int scratch_file PROTO((struct file_info *finfo));
55 static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir,
56 					char *repository, char *update_dir,
57 					List *entries));
58 static int update_dirleave_proc PROTO ((void *callerdat, char *dir,
59 					int err, char *update_dir,
60 					List *entries));
61 static int update_fileproc PROTO ((void *callerdat, struct file_info *));
62 static int update_filesdone_proc PROTO ((void *callerdat, int err,
63 					 char *repository, char *update_dir,
64 					 List *entries));
65 static int write_letter PROTO((char *file, int letter, char *update_dir));
66 #ifdef SERVER_SUPPORT
67 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
68 #else
69 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
70 #endif
71 
72 static char *options = NULL;
73 static char *tag = NULL;
74 static char *date = NULL;
75 static char *join_rev1, *date_rev1;
76 static char *join_rev2, *date_rev2;
77 static int aflag = 0;
78 static int force_tag_match = 1;
79 static int update_build_dirs = 0;
80 static int update_prune_dirs = 0;
81 static int pipeout = 0;
82 #ifdef SERVER_SUPPORT
83 static int patches = 0;
84 #endif
85 static List *ignlist = (List *) NULL;
86 static time_t last_register_time;
87 static const char *const update_usage[] =
88 {
89     "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n",
90     "    [-I ign] [-W spec] [files...]\n",
91     "\t-A\tReset any sticky tags/date/kopts.\n",
92     "\t-P\tPrune empty directories.\n",
93     "\t-d\tBuild directories, like checkout does.\n",
94     "\t-f\tForce a head revision match if tag/date not found.\n",
95     "\t-l\tLocal directory only, no recursion.\n",
96     "\t-R\tProcess directories recursively.\n",
97     "\t-p\tSend updates to standard output (avoids stickiness).\n",
98     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
99     "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
100     "\t-D date\tSet date to update from (is sticky).\n",
101     "\t-j rev\tMerge in changes made between current revision and rev.\n",
102     "\t-I ign\tMore files to ignore (! to reset).\n",
103     "\t-W spec\tWrappers specification line.\n",
104     NULL
105 };
106 
107 /*
108  * update is the argv,argc based front end for arg parsing
109  */
110 int
111 update (argc, argv)
112     int argc;
113     char **argv;
114 {
115     int c, err;
116     int local = 0;			/* recursive by default */
117     int which;				/* where to look for files and dirs */
118 
119     if (argc == -1)
120 	usage (update_usage);
121 
122     ign_setup ();
123     wrap_setup ();
124 
125     /* parse the args */
126     optind = 1;
127     while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:W:")) != -1)
128     {
129 	switch (c)
130 	{
131 	    case 'A':
132 		aflag = 1;
133 		break;
134 	    case 'I':
135 		ign_add (optarg, 0);
136 		break;
137 	    case 'W':
138 		wrap_add (optarg, 0);
139 		break;
140 	    case 'k':
141 		if (options)
142 		    free (options);
143 		options = RCS_check_kflag (optarg);
144 		break;
145 	    case 'l':
146 		local = 1;
147 		break;
148 	    case 'R':
149 		local = 0;
150 		break;
151 	    case 'Q':
152 	    case 'q':
153 #ifdef SERVER_SUPPORT
154 		/* The CVS 1.5 client sends these options (in addition to
155 		   Global_option requests), so we must ignore them.  */
156 		if (!server_active)
157 #endif
158 		    error (1, 0,
159 			   "-q or -Q must be specified before \"%s\"",
160 			   command_name);
161 		break;
162 	    case 'd':
163 		update_build_dirs = 1;
164 		break;
165 	    case 'f':
166 		force_tag_match = 0;
167 		break;
168 	    case 'r':
169 		tag = optarg;
170 		break;
171 	    case 'D':
172 		date = Make_Date (optarg);
173 		break;
174 	    case 'P':
175 		update_prune_dirs = 1;
176 		break;
177 	    case 'p':
178 		pipeout = 1;
179 		noexec = 1;		/* so no locks will be created */
180 		break;
181 	    case 'j':
182 		if (join_rev2)
183 		    error (1, 0, "only two -j options can be specified");
184 		if (join_rev1)
185 		    join_rev2 = optarg;
186 		else
187 		    join_rev1 = optarg;
188 		break;
189 	    case 'u':
190 #ifdef SERVER_SUPPORT
191 		if (server_active)
192 		    patches = 1;
193 		else
194 #endif
195 		    usage (update_usage);
196 		break;
197 	    case '?':
198 	    default:
199 		usage (update_usage);
200 		break;
201 	}
202     }
203     argc -= optind;
204     argv += optind;
205 
206 #ifdef CLIENT_SUPPORT
207     if (client_active)
208     {
209 	/* The first pass does the regular update.  If we receive at least
210 	   one patch which failed, we do a second pass and just fetch
211 	   those files whose patches failed.  */
212 	do
213 	{
214 	    int status;
215 
216 	    start_server ();
217 
218 	    if (local)
219 		send_arg("-l");
220 	    if (update_build_dirs)
221 		send_arg("-d");
222 	    if (pipeout)
223 		send_arg("-p");
224 	    if (!force_tag_match)
225 		send_arg("-f");
226 	    if (aflag)
227 		send_arg("-A");
228 	    if (update_prune_dirs)
229 		send_arg("-P");
230 	    client_prune_dirs = update_prune_dirs;
231 	    option_with_arg ("-r", tag);
232 	    if (options && options[0] != '\0')
233 		send_arg (options);
234 	    if (date)
235 		client_senddate (date);
236 	    if (join_rev1)
237 		option_with_arg ("-j", join_rev1);
238 	    if (join_rev2)
239 		option_with_arg ("-j", join_rev2);
240 	    wrap_send ();
241 
242 	    /* If the server supports the command "update-patches", that means
243 	       that it knows how to handle the -u argument to update, which
244 	       means to send patches instead of complete files.  */
245 	    if (failed_patches == NULL)
246 	    {
247 #ifndef DONT_USE_PATCH
248 		/* Systems which don't have the patch program ported to them
249 		   will want to define DONT_USE_PATCH; then CVS won't try to
250 		   invoke patch.  */
251 		if (supported_request ("update-patches"))
252 		    send_arg ("-u");
253 #endif
254 	    }
255 
256 	    if (failed_patches == NULL)
257 	    {
258 		send_file_names (argc, argv, SEND_EXPAND_WILD);
259 		send_files (argc, argv, local, aflag);
260 	    }
261 	    else
262 	    {
263 		int i;
264 
265 		(void) printf ("%s client: refetching unpatchable files\n",
266 			       program_name);
267 
268 		if (toplevel_wd[0] != '\0'
269 		    && CVS_CHDIR (toplevel_wd) < 0)
270 		{
271 		    error (1, errno, "could not chdir to %s", toplevel_wd);
272 		}
273 
274 		for (i = 0; i < failed_patches_count; i++)
275 		    (void) unlink_file (failed_patches[i]);
276 		send_file_names (failed_patches_count, failed_patches, 0);
277 		send_files (failed_patches_count, failed_patches, local,
278 			    aflag);
279 	    }
280 
281 	    failed_patches = NULL;
282 	    failed_patches_count = 0;
283 
284 	    send_to_server ("update\012", 0);
285 
286 	    status = get_responses_and_close ();
287 	    if (status != 0)
288 		return status;
289 
290 	} while (failed_patches != NULL);
291 
292 	return 0;
293     }
294 #endif
295 
296     if (tag != NULL)
297 	tag_check_valid (tag, argc, argv, local, aflag, "");
298     if (join_rev1 != NULL)
299         tag_check_valid_join (join_rev1, argc, argv, local, aflag, "");
300     if (join_rev2 != NULL)
301         tag_check_valid_join (join_rev2, argc, argv, local, aflag, "");
302 
303     /*
304      * If we are updating the entire directory (for real) and building dirs
305      * as we go, we make sure there is no static entries file and write the
306      * tag file as appropriate
307      */
308     if (argc <= 0 && !pipeout)
309     {
310 	if (update_build_dirs)
311 	{
312 	    if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
313 		error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
314 #ifdef SERVER_SUPPORT
315 	    if (server_active)
316 		server_clear_entstat (".", Name_Repository (NULL, NULL));
317 #endif
318 	}
319 
320 	/* keep the CVS/Tag file current with the specified arguments */
321 	if (aflag || tag || date)
322 	{
323 	    WriteTag ((char *) NULL, tag, date);
324 #ifdef SERVER_SUPPORT
325 	    if (server_active)
326 		server_set_sticky (".", Name_Repository (NULL, NULL), tag, date);
327 #endif
328 	}
329     }
330 
331     /* look for files/dirs locally and in the repository */
332     which = W_LOCAL | W_REPOS;
333 
334     /* look in the attic too if a tag or date is specified */
335     if (tag != NULL || date != NULL || joining())
336 	which |= W_ATTIC;
337 
338     /* call the command line interface */
339     err = do_update (argc, argv, options, tag, date, force_tag_match,
340 		     local, update_build_dirs, aflag, update_prune_dirs,
341 		     pipeout, which, join_rev1, join_rev2, (char *) NULL);
342 
343     /* free the space Make_Date allocated if necessary */
344     if (date != NULL)
345 	free (date);
346 
347     return (err);
348 }
349 
350 /*
351  * Command line interface to update (used by checkout)
352  */
353 int
354 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
355 	   xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir)
356     int argc;
357     char **argv;
358     char *xoptions;
359     char *xtag;
360     char *xdate;
361     int xforce;
362     int local;
363     int xbuild;
364     int xaflag;
365     int xprune;
366     int xpipeout;
367     int which;
368     char *xjoin_rev1;
369     char *xjoin_rev2;
370     char *preload_update_dir;
371 {
372     int err = 0;
373     char *cp;
374 
375     /* fill in the statics */
376     options = xoptions;
377     tag = xtag;
378     date = xdate;
379     force_tag_match = xforce;
380     update_build_dirs = xbuild;
381     aflag = xaflag;
382     update_prune_dirs = xprune;
383     pipeout = xpipeout;
384 
385     /* setup the join support */
386     join_rev1 = xjoin_rev1;
387     join_rev2 = xjoin_rev2;
388     if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
389     {
390 	*cp++ = '\0';
391 	date_rev1 = Make_Date (cp);
392     }
393     else
394 	date_rev1 = (char *) NULL;
395     if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
396     {
397 	*cp++ = '\0';
398 	date_rev2 = Make_Date (cp);
399     }
400     else
401 	date_rev2 = (char *) NULL;
402 
403     /* call the recursion processor */
404     err = start_recursion (update_fileproc, update_filesdone_proc,
405 			   update_dirent_proc, update_dirleave_proc, NULL,
406 			   argc, argv, local, which, aflag, 1,
407 			   preload_update_dir, 1);
408 
409     /* see if we need to sleep before returning */
410     if (last_register_time)
411     {
412 	time_t now;
413 
414 	(void) time (&now);
415 	if (now == last_register_time)
416 	    sleep (1);			/* to avoid time-stamp races */
417     }
418 
419     return (err);
420 }
421 
422 /*
423  * This is the callback proc for update.  It is called for each file in each
424  * directory by the recursion code.  The current directory is the local
425  * instantiation.  file is the file name we are to operate on. update_dir is
426  * set to the path relative to where we started (for pretty printing).
427  * repository is the repository. entries and srcfiles are the pre-parsed
428  * entries and source control files.
429  *
430  * This routine decides what needs to be done for each file and does the
431  * appropriate magic for checkout
432  */
433 static int
434 update_fileproc (callerdat, finfo)
435     void *callerdat;
436     struct file_info *finfo;
437 {
438     int retval;
439     Ctype status;
440     Vers_TS *vers;
441     int resurrecting;
442 
443     resurrecting = 0;
444 
445     status = Classify_File (finfo, tag, date, options, force_tag_match,
446 			    aflag, &vers, pipeout);
447     if (pipeout)
448     {
449 	/*
450 	 * We just return success without doing anything if any of the really
451 	 * funky cases occur
452 	 *
453 	 * If there is still a valid RCS file, do a regular checkout type
454 	 * operation
455 	 */
456 	switch (status)
457 	{
458 	    case T_UNKNOWN:		/* unknown file was explicitly asked
459 					 * about */
460 	    case T_REMOVE_ENTRY:	/* needs to be un-registered */
461 	    case T_ADDED:		/* added but not committed */
462 		retval = 0;
463 		break;
464 	    case T_CONFLICT:		/* old punt-type errors */
465 		retval = 1;
466 		break;
467 	    case T_UPTODATE:		/* file was already up-to-date */
468 	    case T_NEEDS_MERGE:		/* needs merging */
469 	    case T_MODIFIED:		/* locally modified */
470 	    case T_REMOVED:		/* removed but not committed */
471 	    case T_CHECKOUT:		/* needs checkout */
472 #ifdef SERVER_SUPPORT
473 	    case T_PATCH:		/* needs patch */
474 #endif
475 		retval = checkout_file (finfo, vers, 0);
476 		break;
477 
478 	    default:			/* can't ever happen :-) */
479 		error (0, 0,
480 		       "unknown file status %d for file %s", status, finfo->file);
481 		retval = 0;
482 		break;
483 	}
484     }
485     else
486     {
487 	switch (status)
488 	{
489 	    case T_UNKNOWN:		/* unknown file was explicitly asked
490 					 * about */
491 	    case T_UPTODATE:		/* file was already up-to-date */
492 		retval = 0;
493 		break;
494 	    case T_CONFLICT:		/* old punt-type errors */
495 		retval = 1;
496 		(void) write_letter (finfo->file, 'C', finfo->update_dir);
497 		break;
498 	    case T_NEEDS_MERGE:		/* needs merging */
499 		if (noexec)
500 		{
501 		    retval = 1;
502 		    (void) write_letter (finfo->file, 'C', finfo->update_dir);
503 		}
504 		else
505 		{
506 		    if (wrap_merge_is_copy (finfo->file))
507 			/* Should we be warning the user that we are
508 			 * overwriting the user's copy of the file?  */
509 			retval =
510 			  checkout_file (finfo, vers, 0);
511 		    else
512 			retval = merge_file (finfo, vers);
513 		}
514 		break;
515 	    case T_MODIFIED:		/* locally modified */
516 		retval = 0;
517 		if (vers->ts_conflict)
518 		{
519 		    char *filestamp;
520 		    int retcode;
521 
522 		    /*
523 		     * If the timestamp has changed and no conflict indicators
524 		     * are found, it isn't a 'C' any more.
525 		     */
526 #ifdef SERVER_SUPPORT
527 		    if (server_active)
528 			retcode = vers->ts_conflict[0] != '=';
529 		    else {
530 			filestamp = time_stamp (finfo->file);
531 			retcode = strcmp (vers->ts_conflict, filestamp);
532 			free (filestamp);
533 		    }
534 #else
535 		    filestamp = time_stamp (finfo->file);
536 		    retcode = strcmp (vers->ts_conflict, filestamp);
537 		    free (filestamp);
538 #endif
539 
540 		    if (retcode)
541 		    {
542 			/*
543 			 * If the timestamps differ, look for Conflict
544 			 * indicators to see if 'C' anyway.
545 			 */
546 			run_setup ("%s", GREP);
547 			run_arg (RCS_MERGE_PAT);
548 			run_arg (finfo->file);
549 			retcode = run_exec (RUN_TTY, DEVNULL,
550 					    RUN_TTY,RUN_NORMAL);
551 			if (retcode == -1)
552 			{
553 			    error (1, errno,
554 				"fork failed while examining conflict in `%s'",
555 				       finfo->fullname);
556 			}
557 		    }
558 		    if (!retcode)
559 		    {
560 			(void) write_letter (finfo->file, 'C', finfo->update_dir);
561 			retval = 1;
562 		    }
563 		    else
564 		    {
565 			/* Reregister to clear conflict flag. */
566 			Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs,
567 				  vers->options, vers->tag,
568 				  vers->date, (char *)0);
569 		    }
570 		}
571 		if (!retval)
572 		    retval = write_letter (finfo->file, 'M', finfo->update_dir);
573 		break;
574 #ifdef SERVER_SUPPORT
575 	    case T_PATCH:		/* needs patch */
576 		if (patches)
577 		{
578 		    int docheckout;
579 		    struct stat file_info;
580 		    unsigned char checksum[16];
581 
582 		    retval = patch_file (finfo,
583 					 vers, &docheckout,
584 					 &file_info, checksum);
585 		    if (! docheckout)
586 		    {
587 		        if (server_active && retval == 0)
588 			    server_updated (finfo, vers,
589 					    SERVER_PATCHED, &file_info,
590 					    checksum);
591 			break;
592 		    }
593 		}
594 		/* Fall through.  */
595 		/* If we're not running as a server, just check the
596 		   file out.  It's simpler and faster than starting up
597 		   two new processes (diff and patch).  */
598 		/* Fall through.  */
599 #endif
600 	    case T_CHECKOUT:		/* needs checkout */
601 		retval = checkout_file (finfo, vers, 0);
602 #ifdef SERVER_SUPPORT
603 		if (server_active && retval == 0)
604 		    server_updated (finfo, vers,
605 				    SERVER_UPDATED, (struct stat *) NULL,
606 				    (unsigned char *) NULL);
607 #endif
608 		break;
609 	    case T_ADDED:		/* added but not committed */
610 		retval = write_letter (finfo->file, 'A', finfo->update_dir);
611 		break;
612 	    case T_REMOVED:		/* removed but not committed */
613 		retval = write_letter (finfo->file, 'R', finfo->update_dir);
614 		break;
615 	    case T_REMOVE_ENTRY:	/* needs to be un-registered */
616 		retval = scratch_file (finfo);
617 #ifdef SERVER_SUPPORT
618 		if (server_active && retval == 0)
619 		{
620 		    if (vers->ts_user == NULL)
621 			server_scratch_entry_only ();
622 		    server_updated (finfo, vers,
623 				    SERVER_UPDATED, (struct stat *) NULL,
624 				    (unsigned char *) NULL);
625 		}
626 #endif
627 		break;
628 	    default:			/* can't ever happen :-) */
629 		error (0, 0,
630 		       "unknown file status %d for file %s", status, finfo->file);
631 		retval = 0;
632 		break;
633 	}
634     }
635 
636     /* only try to join if things have gone well thus far */
637     if (retval == 0 && join_rev1)
638 	join_file (finfo, vers);
639 
640     /* if this directory has an ignore list, add this file to it */
641     if (ignlist)
642     {
643 	Node *p;
644 
645 	p = getnode ();
646 	p->type = FILES;
647 	p->key = xstrdup (finfo->file);
648 	if (addnode (ignlist, p) != 0)
649 	    freenode (p);
650     }
651 
652     freevers_ts (&vers);
653     return (retval);
654 }
655 
656 static void update_ignproc PROTO ((char *, char *));
657 
658 static void
659 update_ignproc (file, dir)
660     char *file;
661     char *dir;
662 {
663     (void) write_letter (file, '?', dir);
664 }
665 
666 /* ARGSUSED */
667 static int
668 update_filesdone_proc (callerdat, err, repository, update_dir, entries)
669     void *callerdat;
670     int err;
671     char *repository;
672     char *update_dir;
673     List *entries;
674 {
675     /* if this directory has an ignore list, process it then free it */
676     if (ignlist)
677     {
678 	ignore_files (ignlist, entries, update_dir, update_ignproc);
679 	dellist (&ignlist);
680     }
681 
682     /* Clean up CVS admin dirs if we are export */
683     if (strcmp (command_name, "export") == 0)
684     {
685 	/* I'm not sure the existence_error is actually possible (except
686 	   in cases where we really should print a message), but since
687 	   this code used to ignore all errors, I'll play it safe.  */
688 	if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
689 	    error (0, errno, "cannot remove %s directory", CVSADM);
690     }
691 #ifdef SERVER_SUPPORT
692     else if (!server_active && !pipeout)
693 #else
694     else if (!pipeout)
695 #endif /* SERVER_SUPPORT */
696     {
697         /* If there is no CVS/Root file, add one */
698         if (!isfile (CVSADM_ROOT))
699 	    Create_Root ((char *) NULL, CVSroot_original);
700     }
701 
702     return (err);
703 }
704 
705 /*
706  * update_dirent_proc () is called back by the recursion processor before a
707  * sub-directory is processed for update.  In this case, update_dirent proc
708  * will probably create the directory unless -d isn't specified and this is a
709  * new directory.  A return code of 0 indicates the directory should be
710  * processed by the recursion code.  A return of non-zero indicates the
711  * recursion code should skip this directory.
712  */
713 static Dtype
714 update_dirent_proc (callerdat, dir, repository, update_dir, entries)
715     void *callerdat;
716     char *dir;
717     char *repository;
718     char *update_dir;
719     List *entries;
720 {
721     if (ignore_directory (update_dir))
722     {
723 	/* print the warm fuzzy message */
724 	if (!quiet)
725 	  error (0, 0, "Ignoring %s", update_dir);
726         return R_SKIP_ALL;
727     }
728 
729     if (!isdir (dir))
730     {
731 	/* if we aren't building dirs, blow it off */
732 	if (!update_build_dirs)
733 	    return (R_SKIP_ALL);
734 
735 	if (noexec)
736 	{
737 	    /* ignore the missing dir if -n is specified */
738 	    error (0, 0, "New directory `%s' -- ignored", dir);
739 	    return (R_SKIP_ALL);
740 	}
741 	else
742 	{
743 	    /* otherwise, create the dir and appropriate adm files */
744 	    make_directory (dir);
745 	    Create_Admin (dir, update_dir, repository, tag, date);
746 	    Subdir_Register (entries, (char *) NULL, dir);
747 	}
748     }
749     /* Do we need to check noexec here? */
750     else if (!pipeout)
751     {
752 	char *cvsadmdir;
753 
754 	/* The directory exists.  Check to see if it has a CVS
755 	   subdirectory.  */
756 
757 	cvsadmdir = xmalloc (strlen (dir) + 80);
758 	strcpy (cvsadmdir, dir);
759 	strcat (cvsadmdir, "/");
760 	strcat (cvsadmdir, CVSADM);
761 
762 	if (!isdir (cvsadmdir))
763 	{
764 	    /* We cannot successfully recurse into a directory without a CVS
765 	       subdirectory.  Generally we will have already printed
766 	       "? foo".  */
767 	    free (cvsadmdir);
768 	    return R_SKIP_ALL;
769 	}
770 	free (cvsadmdir);
771     }
772 
773     /*
774      * If we are building dirs and not going to stdout, we make sure there is
775      * no static entries file and write the tag file as appropriate
776      */
777     if (!pipeout)
778     {
779 	if (update_build_dirs)
780 	{
781 	    char tmp[PATH_MAX];
782 
783 	    (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
784 	    if (unlink_file (tmp) < 0 && ! existence_error (errno))
785 		error (1, errno, "cannot remove file %s", tmp);
786 #ifdef SERVER_SUPPORT
787 	    if (server_active)
788 		server_clear_entstat (update_dir, repository);
789 #endif
790 	}
791 
792 	/* keep the CVS/Tag file current with the specified arguments */
793 	if (aflag || tag || date)
794 	{
795 	    WriteTag (dir, tag, date);
796 #ifdef SERVER_SUPPORT
797 	    if (server_active)
798 		server_set_sticky (update_dir, repository, tag, date);
799 #endif
800 	}
801 
802 	/* initialize the ignore list for this directory */
803 	ignlist = getlist ();
804     }
805 
806     /* print the warm fuzzy message */
807     if (!quiet)
808 	error (0, 0, "Updating %s", update_dir);
809 
810     return (R_PROCESS);
811 }
812 
813 /*
814  * update_dirleave_proc () is called back by the recursion code upon leaving
815  * a directory.  It will prune empty directories if needed and will execute
816  * any appropriate update programs.
817  */
818 /* ARGSUSED */
819 static int
820 update_dirleave_proc (callerdat, dir, err, update_dir, entries)
821     void *callerdat;
822     char *dir;
823     int err;
824     char *update_dir;
825     List *entries;
826 {
827     FILE *fp;
828 
829     /* run the update_prog if there is one */
830     if (err == 0 && !pipeout && !noexec &&
831 	(fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL)
832     {
833 	char *cp;
834 	char *repository;
835 	char line[MAXLINELEN];
836 
837 	repository = Name_Repository ((char *) NULL, update_dir);
838 	if (fgets (line, sizeof (line), fp) != NULL)
839 	{
840 	    if ((cp = strrchr (line, '\n')) != NULL)
841 		*cp = '\0';
842 	    run_setup ("%s %s", line, repository);
843 	    (void) printf ("%s %s: Executing '", program_name, command_name);
844 	    run_print (stdout);
845 	    (void) printf ("'\n");
846 	    (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
847 	}
848 	(void) fclose (fp);
849 	free (repository);
850     }
851 
852     if (strchr (dir, '/') == NULL)
853     {
854 	/* FIXME: chdir ("..") loses with symlinks.  */
855 	/* Prune empty dirs on the way out - if necessary */
856 	(void) CVS_CHDIR ("..");
857 	if (update_prune_dirs && isemptydir (dir))
858 	{
859 	    /* I'm not sure the existence_error is actually possible (except
860 	       in cases where we really should print a message), but since
861 	       this code used to ignore all errors, I'll play it safe.	*/
862 	    if (unlink_file_dir (dir) < 0 && !existence_error (errno))
863 		error (0, errno, "cannot remove %s directory", dir);
864 	    Subdir_Deregister (entries, (char *) NULL, dir);
865 	}
866     }
867 
868     return (err);
869 }
870 
871 /*
872  * Returns 1 if the argument directory is completely empty, other than the
873  * existence of the CVS directory entry.  Zero otherwise.
874  */
875 static int
876 isemptydir (dir)
877     char *dir;
878 {
879     DIR *dirp;
880     struct dirent *dp;
881 
882     if ((dirp = CVS_OPENDIR (dir)) == NULL)
883     {
884 	error (0, 0, "cannot open directory %s for empty check", dir);
885 	return (0);
886     }
887     while ((dp = readdir (dirp)) != NULL)
888     {
889 	if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
890 	    strcmp (dp->d_name, CVSADM) != 0)
891 	{
892 	    (void) closedir (dirp);
893 	    return (0);
894 	}
895     }
896     (void) closedir (dirp);
897     return (1);
898 }
899 
900 /*
901  * scratch the Entries file entry associated with a file
902  */
903 static int
904 scratch_file (finfo)
905     struct file_info *finfo;
906 {
907     history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
908     Scratch_Entry (finfo->entries, finfo->file);
909     if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
910 	error (0, errno, "unable to remove %s", finfo->fullname);
911     return (0);
912 }
913 
914 /*
915  * Check out a file.
916  */
917 static int
918 checkout_file (finfo, vers_ts, adding)
919     struct file_info *finfo;
920     Vers_TS *vers_ts;
921     int adding;
922 {
923     char backup[PATH_MAX];
924     int set_time, retval = 0;
925     int retcode = 0;
926     int status;
927     int file_is_dead;
928 
929     /* don't screw with backup files if we're going to stdout */
930     if (!pipeout)
931     {
932 	(void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
933 	if (isfile (finfo->file))
934 	    rename_file (finfo->file, backup);
935 	else
936 	    (void) unlink_file (backup);
937     }
938 
939     file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
940 
941     if (!file_is_dead)
942     {
943 	/*
944 	 * if we are checking out to stdout, print a nice message to
945 	 * stderr, and add the -p flag to the command */
946 	if (pipeout)
947 	{
948 	    if (!quiet)
949 	    {
950 		(void) fprintf (stderr, "\
951 ===================================================================\n");
952 		(void) fprintf (stderr, "Checking out %s\n", finfo->fullname);
953 		(void) fprintf (stderr, "RCS:  %s\n", vers_ts->srcfile->path);
954 		(void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs);
955 		(void) fprintf (stderr, "***************\n");
956 	    }
957 	}
958 
959 	status = RCS_checkout (vers_ts->srcfile,
960 			       pipeout ? NULL : finfo->file,
961 			       vers_ts->vn_rcs, vers_ts->vn_tag,
962 			       vers_ts->options, RUN_TTY);
963     }
964     if (file_is_dead || status == 0)
965     {
966 	if (!pipeout)
967 	{
968 	    Vers_TS *xvers_ts;
969 
970 	    if (cvswrite == TRUE
971 		&& !file_is_dead
972 		&& !fileattr_get (finfo->file, "_watched"))
973 		xchmod (finfo->file, 1);
974 
975 	    {
976 		/* A newly checked out file is never under the spell
977 		   of "cvs edit".  If we think we were editing it
978 		   from a previous life, clean up.  Would be better to
979 		   check for same the working directory instead of
980 		   same user, but that is hairy.  */
981 
982 		struct addremove_args args;
983 
984 		editor_set (finfo->file, getcaller (), NULL);
985 
986 		memset (&args, 0, sizeof args);
987 		args.remove_temp = 1;
988 		watch_modify_watchers (finfo->file, &args);
989 	    }
990 
991 	    /* set the time from the RCS file iff it was unknown before */
992 	    if (vers_ts->vn_user == NULL ||
993 		strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
994 	    {
995 		set_time = 1;
996 	    }
997 	    else
998 		set_time = 0;
999 
1000 	    wrap_fromcvs_process_file (finfo->file);
1001 
1002 	    xvers_ts = Version_TS (finfo, options, tag, date,
1003 				   force_tag_match, set_time);
1004 	    if (strcmp (xvers_ts->options, "-V4") == 0)
1005 		xvers_ts->options[0] = '\0';
1006 
1007 	    (void) time (&last_register_time);
1008 
1009 	    if (file_is_dead)
1010 	    {
1011 		if (xvers_ts->vn_user != NULL)
1012 		{
1013 		    error (0, 0,
1014 			   "warning: %s is not (any longer) pertinent",
1015 			   finfo->fullname);
1016 		}
1017 		Scratch_Entry (finfo->entries, finfo->file);
1018 #ifdef SERVER_SUPPORT
1019 		if (server_active && xvers_ts->ts_user == NULL)
1020 		    server_scratch_entry_only ();
1021 #endif
1022 		/* FIXME: Rather than always unlink'ing, and ignoring the
1023 		   existence_error, we should do the unlink only if
1024 		   vers_ts->ts_user is non-NULL.  Then there would be no
1025 		   need to ignore an existence_error (for example, if the
1026 		   user removes the file while we are running).  */
1027 		if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1028 		{
1029 		    error (0, errno, "cannot remove %s", finfo->fullname);
1030 		}
1031 	    }
1032 	    else
1033 		Register (finfo->entries, finfo->file,
1034 			  adding ? "0" : xvers_ts->vn_rcs,
1035 			  xvers_ts->ts_user, xvers_ts->options,
1036 			  xvers_ts->tag, xvers_ts->date,
1037 			  (char *)0); /* Clear conflict flag on fresh checkout */
1038 
1039 	    /* fix up the vers structure, in case it is used by join */
1040 	    if (join_rev1)
1041 	    {
1042 		if (vers_ts->vn_user != NULL)
1043 		    free (vers_ts->vn_user);
1044 		if (vers_ts->vn_rcs != NULL)
1045 		    free (vers_ts->vn_rcs);
1046 		vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1047 		vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1048 	    }
1049 
1050 	    /* If this is really Update and not Checkout, recode history */
1051 	    if (strcmp (command_name, "update") == 0)
1052 		history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1053 			       finfo->repository);
1054 
1055 	    freevers_ts (&xvers_ts);
1056 
1057 	    if (!really_quiet && !file_is_dead)
1058 	    {
1059 		write_letter (finfo->file, 'U', finfo->update_dir);
1060 	    }
1061 	}
1062     }
1063     else
1064     {
1065 	int old_errno = errno;		/* save errno value over the rename */
1066 
1067 	if (!pipeout && isfile (backup))
1068 	    rename_file (backup, finfo->file);
1069 
1070 	error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1071 	       "could not check out %s", finfo->fullname);
1072 
1073 	retval = retcode;
1074     }
1075 
1076     if (!pipeout)
1077 	(void) unlink_file (backup);
1078 
1079     return (retval);
1080 }
1081 
1082 #ifdef SERVER_SUPPORT
1083 /* Patch a file.  Runs rcsdiff.  This is only done when running as the
1084  * server.  The hope is that the diff will be smaller than the file
1085  * itself.
1086  */
1087 static int
1088 patch_file (finfo, vers_ts, docheckout, file_info, checksum)
1089     struct file_info *finfo;
1090     Vers_TS *vers_ts;
1091     int *docheckout;
1092     struct stat *file_info;
1093     unsigned char *checksum;
1094 {
1095     char backup[PATH_MAX];
1096     char file1[PATH_MAX];
1097     char file2[PATH_MAX];
1098     int retval = 0;
1099     int retcode = 0;
1100     int fail;
1101     long file_size;
1102     FILE *e;
1103 
1104     *docheckout = 0;
1105 
1106     if (pipeout || joining ())
1107     {
1108 	*docheckout = 1;
1109 	return 0;
1110     }
1111 
1112     (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1113     if (isfile (finfo->file))
1114         rename_file (finfo->file, backup);
1115     else
1116         (void) unlink_file (backup);
1117 
1118     (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1119     (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1120 
1121     fail = 0;
1122 
1123     /* We need to check out both revisions first, to see if either one
1124        has a trailing newline.  Because of this, we don't use rcsdiff,
1125        but just use diff.  */
1126     if (noexec)
1127 	retcode = 0;
1128     else
1129 	retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1130 				vers_ts->vn_user, (char *) NULL,
1131 				vers_ts->options, file1);
1132     if (retcode != 0)
1133         fail = 1;
1134     else
1135     {
1136         e = CVS_FOPEN (file1, "r");
1137 	if (e == NULL)
1138 	    fail = 1;
1139 	else
1140 	{
1141 	    if (fseek (e, (long) -1, SEEK_END) == 0
1142 		&& getc (e) != '\n')
1143 	    {
1144 	        fail = 1;
1145 	    }
1146 	    fclose (e);
1147 	}
1148     }
1149 
1150     if (! fail)
1151     {
1152         /* Check it out into finfo->file, and then move to file2, so that we
1153            can get the right modes into *FILE_INFO.  We can't check it
1154            out directly into file2 because co doesn't understand how
1155            to do that.  */
1156 	retcode = RCS_checkout (vers_ts->srcfile, finfo->file,
1157 				vers_ts->vn_rcs, (char *) NULL,
1158 				vers_ts->options, RUN_TTY);
1159 	if (retcode != 0)
1160 	    fail = 1;
1161 	else
1162 	{
1163 	    if (!isreadable (finfo->file))
1164 	    {
1165 	        /* File is dead.  */
1166 	        fail = 1;
1167 	    }
1168 	    else
1169 	    {
1170 	        rename_file (finfo->file, file2);
1171 		if (cvswrite == TRUE
1172 		    && !fileattr_get (finfo->file, "_watched"))
1173 		    xchmod (file2, 1);
1174 		e = CVS_FOPEN (file2, "r");
1175 		if (e == NULL)
1176 		    fail = 1;
1177 		else
1178 		{
1179 		    struct MD5Context context;
1180 		    int nl;
1181 		    unsigned char buf[8192];
1182 		    unsigned len;
1183 
1184 		    nl = 0;
1185 
1186 		    /* Compute the MD5 checksum and make sure there is
1187                        a trailing newline.  */
1188 		    MD5Init (&context);
1189 		    while ((len = fread (buf, 1, sizeof buf, e)) != 0)
1190 		    {
1191 			nl = buf[len - 1] == '\n';
1192 		        MD5Update (&context, buf, len);
1193 		    }
1194 		    MD5Final (checksum, &context);
1195 
1196 		    if (ferror (e) || ! nl)
1197 		    {
1198 		        fail = 1;
1199 		    }
1200 
1201 		    fseek(e, 0L, SEEK_END);
1202 		    file_size = ftell(e);
1203 
1204 		    fclose (e);
1205 		}
1206 	    }
1207 	}
1208     }
1209 
1210     retcode = 0;
1211     if (! fail)
1212     {
1213 	/* FIXME: This whole thing with diff/patch is rather more
1214 	   convoluted than necessary (lots of forks and execs, need to
1215 	   worry about versions of diff and patch, etc.).  Also, we
1216 	   send context lines which aren't needed (in the rare case in
1217 	   which the diff doesn't apply, the checksum would catches it).
1218 	   Solution perhaps is to librarify the RCS routines which apply
1219 	   deltas or something equivalent.  */
1220 	/* This is -c, not -u, because we have no way of knowing which
1221 	   DIFF is in use.  */
1222 	run_setup ("%s -c %s %s", DIFF, file1, file2);
1223 
1224 	/* A retcode of 0 means no differences.  1 means some differences.  */
1225 	if ((retcode = run_exec (RUN_TTY, finfo->file, RUN_TTY, RUN_NORMAL)) != 0
1226 	    && retcode != 1)
1227 	{
1228 	    fail = 1;
1229 	}
1230 	else
1231 	{
1232 #define BINARY "Binary"
1233 	    char buf[sizeof BINARY];
1234 	    unsigned int c;
1235 
1236 	    /* Check the diff output to make sure patch will be handle it.  */
1237 	    e = CVS_FOPEN (finfo->file, "r");
1238 	    if (e == NULL)
1239 		error (1, errno, "could not open diff output file %s",
1240 		       finfo->fullname);
1241 	    c = fread (buf, 1, sizeof BINARY - 1, e);
1242 	    buf[c] = '\0';
1243 	    if (strcmp (buf, BINARY) == 0)
1244 	    {
1245 		/* These are binary files.  We could use diff -a, but
1246 		   patch can't handle that.  */
1247 		fail = 1;
1248 	    }
1249 	    else {
1250 		/*
1251 		 * Don't send a diff if just sending the entire file
1252 		 * would be smaller
1253 		 */
1254 		fseek(e, 0L, SEEK_END);
1255 		if (file_size < ftell(e))
1256 		    fail = 1;
1257 	    }
1258 
1259 	    fclose (e);
1260 	}
1261     }
1262 
1263     if (! fail)
1264     {
1265         Vers_TS *xvers_ts;
1266 
1267         /* This stuff is just copied blindly from checkout_file.  I
1268 	   don't really know what it does.  */
1269         xvers_ts = Version_TS (finfo, options, tag, date,
1270 			       force_tag_match, 0);
1271 	if (strcmp (xvers_ts->options, "-V4") == 0)
1272 	    xvers_ts->options[0] = '\0';
1273 
1274 	Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1275 		  xvers_ts->ts_user, xvers_ts->options,
1276 		  xvers_ts->tag, xvers_ts->date, NULL);
1277 
1278 	if ( CVS_STAT (file2, file_info) < 0)
1279 	    error (1, errno, "could not stat %s", file2);
1280 
1281 	/* If this is really Update and not Checkout, recode history */
1282 	if (strcmp (command_name, "update") == 0)
1283 	    history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1284 			   finfo->repository);
1285 
1286 	freevers_ts (&xvers_ts);
1287 
1288 	if (!really_quiet)
1289 	{
1290 	    write_letter (finfo->file, 'P', finfo->update_dir);
1291 	}
1292     }
1293     else
1294     {
1295 	int old_errno = errno;		/* save errno value over the rename */
1296 
1297 	if (isfile (backup))
1298 	    rename_file (backup, finfo->file);
1299 
1300 	if (retcode != 0 && retcode != 1)
1301 	    error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1302 		   "could not diff %s", finfo->fullname);
1303 
1304 	*docheckout = 1;
1305 	retval = retcode;
1306     }
1307 
1308     (void) unlink_file (backup);
1309     (void) unlink_file (file1);
1310     (void) unlink_file (file2);
1311 
1312     return (retval);
1313 }
1314 #endif
1315 
1316 /*
1317  * Several of the types we process only print a bit of information consisting
1318  * of a single letter and the name.
1319  */
1320 static int
1321 write_letter (file, letter, update_dir)
1322     char *file;
1323     int letter;
1324     char *update_dir;
1325 {
1326     if (!really_quiet)
1327     {
1328 	char buf[2];
1329 	buf[0] = letter;
1330 	buf[1] = ' ';
1331 	cvs_output (buf, 2);
1332 	if (update_dir[0])
1333 	{
1334 	    cvs_output (update_dir, 0);
1335 	    cvs_output ("/", 1);
1336 	}
1337 	cvs_output (file, 0);
1338 	cvs_output ("\n", 1);
1339     }
1340     return (0);
1341 }
1342 
1343 /*
1344  * Do all the magic associated with a file which needs to be merged
1345  */
1346 static int
1347 merge_file (finfo, vers)
1348     struct file_info *finfo;
1349     Vers_TS *vers;
1350 {
1351     char backup[PATH_MAX];
1352     int status;
1353     int retcode = 0;
1354 
1355     /*
1356      * The users currently modified file is moved to a backup file name
1357      * ".#filename.version", so that it will stay around for a few days
1358      * before being automatically removed by some cron daemon.  The "version"
1359      * is the version of the file that the user was most up-to-date with
1360      * before the merge.
1361      */
1362     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1363 
1364     (void) unlink_file (backup);
1365     copy_file (finfo->file, backup);
1366     xchmod (finfo->file, 1);
1367 
1368     if (strcmp (vers->options, "-kb") == 0)
1369     {
1370 	/* For binary files, a merge is always a conflict.  We give the
1371 	   user the two files, and let them resolve it.  It is possible
1372 	   that we should require a "touch foo" or similar step before
1373 	   we allow a checkin.  */
1374 	status = checkout_file (finfo, vers, 0);
1375 #ifdef SERVER_SUPPORT
1376 	/* Send the new contents of the file before the message.  If we
1377 	   wanted to be totally correct, we would have the client write
1378 	   the message only after the file has safely been written.  */
1379 	if (server_active)
1380 	{
1381 	    server_copy_file (finfo->file, finfo->update_dir,
1382 			      finfo->repository, backup);
1383 	    server_updated (finfo, vers, SERVER_MERGED,
1384 			    (struct stat *) NULL, (unsigned char *) NULL);
1385 	}
1386 #endif
1387 	error (0, 0, "binary file needs merge");
1388 	error (0, 0, "revision %s from repository is now in %s",
1389 	       vers->vn_rcs, finfo->fullname);
1390 	error (0, 0, "file from working directory is now in %s", backup);
1391 	write_letter (finfo->file, 'C', finfo->update_dir);
1392 
1393 	history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
1394 	return 0;
1395     }
1396 
1397     status = RCS_merge(vers->srcfile->path,
1398 		       vers->options, vers->vn_user, vers->vn_rcs);
1399     if (status != 0 && status != 1)
1400     {
1401 	error (0, status == -1 ? errno : 0,
1402 	       "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
1403 	error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
1404 	       finfo->fullname, backup);
1405 	rename_file (backup, finfo->file);
1406 	return (1);
1407     }
1408 
1409     if (strcmp (vers->options, "-V4") == 0)
1410 	vers->options[0] = '\0';
1411     (void) time (&last_register_time);
1412     {
1413 	char *cp = 0;
1414 
1415 	if (status)
1416 	    cp = time_stamp (finfo->file);
1417 	Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, vers->options,
1418 		  vers->tag, vers->date, cp);
1419 	if (cp)
1420 	    free (cp);
1421     }
1422 
1423     /* fix up the vers structure, in case it is used by join */
1424     if (join_rev1)
1425     {
1426 	if (vers->vn_user != NULL)
1427 	    free (vers->vn_user);
1428 	vers->vn_user = xstrdup (vers->vn_rcs);
1429     }
1430 
1431 #ifdef SERVER_SUPPORT
1432     /* Send the new contents of the file before the message.  If we
1433        wanted to be totally correct, we would have the client write
1434        the message only after the file has safely been written.  */
1435     if (server_active)
1436     {
1437         server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
1438 			  backup);
1439 	server_updated (finfo, vers, SERVER_MERGED,
1440 			(struct stat *) NULL, (unsigned char *) NULL);
1441     }
1442 #endif
1443 
1444     if (!noexec && !xcmp (backup, finfo->file))
1445     {
1446 	printf ("%s already contains the differences between %s and %s\n",
1447 		finfo->fullname, vers->vn_user, vers->vn_rcs);
1448 	history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
1449 	return (0);
1450     }
1451 
1452     if (status == 1)
1453     {
1454 	if (!noexec)
1455 	    error (0, 0, "conflicts found in %s", finfo->fullname);
1456 
1457 	write_letter (finfo->file, 'C', finfo->update_dir);
1458 
1459 	history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
1460 
1461     }
1462     else if (retcode == -1)
1463     {
1464 	error (1, errno, "fork failed while examining update of %s", finfo->fullname);
1465     }
1466     else
1467     {
1468 	write_letter (finfo->file, 'M', finfo->update_dir);
1469 	history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
1470     }
1471     return (0);
1472 }
1473 
1474 /*
1475  * Do all the magic associated with a file which needs to be joined
1476  * (-j option)
1477  */
1478 static void
1479 join_file (finfo, vers)
1480     struct file_info *finfo;
1481     Vers_TS *vers;
1482 {
1483     char backup[PATH_MAX];
1484     char *options;
1485     int status;
1486 
1487     char *rev1;
1488     char *rev2;
1489     char *jrev1;
1490     char *jrev2;
1491     char *jdate1;
1492     char *jdate2;
1493 
1494     jrev1 = join_rev1;
1495     jrev2 = join_rev2;
1496     jdate1 = date_rev1;
1497     jdate2 = date_rev2;
1498 
1499     if (wrap_merge_is_copy (finfo->file))
1500     {
1501 	error (0, 0,
1502 	       "Cannot merge %s because it is a merge-by-copy file.",
1503 	       finfo->fullname);
1504 	return;
1505     }
1506 
1507     /* Determine if we need to do anything at all.  */
1508     if (vers->srcfile == NULL ||
1509 	vers->srcfile->path == NULL)
1510     {
1511 	return;
1512     }
1513 
1514     /* If only one join revision is specified, it becomes the second
1515        revision.  */
1516     if (jrev2 == NULL)
1517     {
1518 	jrev2 = jrev1;
1519 	jrev1 = NULL;
1520 	jdate2 = jdate1;
1521 	jdate1 = NULL;
1522     }
1523 
1524     /* Convert the second revision, walking branches and dates.  */
1525     rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
1526 
1527     /* If this is a merge of two revisions, get the first revision.
1528        If only one join tag was specified, then the first revision is
1529        the greatest common ancestor of the second revision and the
1530        working file.  */
1531     if (jrev1 != NULL)
1532 	rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL);
1533     else
1534     {
1535 	/* Note that we use vn_rcs here, since vn_user may contain a
1536            special string such as "-nn".  */
1537 	if (vers->vn_rcs == NULL)
1538 	    rev1 = NULL;
1539 	else if (rev2 == NULL)
1540 	{
1541 	    /* This means that the file never existed on the branch.
1542                It does not mean that the file was removed on the
1543                branch: that case is represented by a dead rev2.  If
1544                the file never existed on the branch, then we have
1545                nothing to merge, so we just return.  */
1546 	    return;
1547 	}
1548 	else
1549 	    rev1 = gca (vers->vn_rcs, rev2);
1550     }
1551 
1552     /* Handle a nonexistent or dead merge target.  */
1553     if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
1554     {
1555 	char *mrev;
1556 
1557 	if (rev2 != NULL)
1558 	    free (rev2);
1559 
1560 	/* If the first revision doesn't exist either, then there is
1561            no change between the two revisions, so we don't do
1562            anything.  */
1563 	if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
1564 	{
1565 	    if (rev1 != NULL)
1566 		free (rev1);
1567 	    return;
1568 	}
1569 
1570 	/* If we are merging two revisions, then the file was removed
1571 	   between the first revision and the second one.  In this
1572 	   case we want to mark the file for removal.
1573 
1574 	   If we are merging one revision, then the file has been
1575 	   removed between the greatest common ancestor and the merge
1576 	   revision.  From the perspective of the branch on to which
1577 	   we ar emerging, which may be the trunk, either 1) the file
1578 	   does not currently exist on the target, or 2) the file has
1579 	   not been modified on the target branch since the greatest
1580 	   common ancestor, or 3) the file has been modified on the
1581 	   target branch since the greatest common ancestor.  In case
1582 	   1 there is nothing to do.  In case 2 we mark the file for
1583 	   removal.  In case 3 we have a conflict.
1584 
1585 	   Note that the handling is slightly different depending upon
1586 	   whether one or two join targets were specified.  If two
1587 	   join targets were specified, we don't check whether the
1588 	   file was modified since a given point.  My reasoning is
1589 	   that if you ask for an explicit merge between two tags,
1590 	   then you want to merge in whatever was changed between
1591 	   those two tags.  If a file was removed between the two
1592 	   tags, then you want it to be removed.  However, if you ask
1593 	   for a merge of a branch, then you want to merge in all
1594 	   changes which were made on the branch.  If a file was
1595 	   removed on the branch, that is a change to the file.  If
1596 	   the file was also changed on the main line, then that is
1597 	   also a change.  These two changes--the file removal and the
1598 	   modification--must be merged.  This is a conflict.  */
1599 
1600 	/* If the user file is dead, or does not exist, or has been
1601            marked for removal, then there is nothing to do.  */
1602 	if (vers->vn_user == NULL
1603 	    || vers->vn_user[0] == '-'
1604 	    || RCS_isdead (vers->srcfile, vers->vn_user))
1605 	{
1606 	    if (rev1 != NULL)
1607 		free (rev1);
1608 	    return;
1609 	}
1610 
1611 	/* If the user file has been marked for addition, or has been
1612 	   locally modified, then we have a conflict which we can not
1613 	   resolve.  No_Difference will already have been called in
1614 	   this case, so comparing the timestamps is sufficient to
1615 	   determine whether the file is locally modified.  */
1616 	if (strcmp (vers->vn_user, "0") == 0
1617 	    || (vers->ts_user != NULL
1618 		&& strcmp (vers->ts_user, vers->ts_rcs) != 0))
1619 	{
1620 	    if (jdate2 != NULL)
1621 		error (0, 0,
1622 		       "file %s is locally modified, but has been removed in revision %s as of %s",
1623 		       finfo->fullname, jrev2, jdate2);
1624 	    else
1625 		error (0, 0,
1626 		       "file %s is locally modified, but has been removed in revision %s",
1627 		       finfo->fullname, jrev2);
1628 
1629 	    /* FIXME: Should we arrange to return a non-zero exit
1630                status?  */
1631 
1632 	    if (rev1 != NULL)
1633 		free (rev1);
1634 
1635 	    return;
1636 	}
1637 
1638 	/* If only one join tag was specified, and the user file has
1639            been changed since the greatest common ancestor (rev1),
1640            then there is a conflict we can not resolve.  See above for
1641            the rationale.  */
1642 	if (join_rev2 == NULL
1643 	    && strcmp (rev1, vers->vn_user) != 0)
1644 	{
1645 	    if (jdate2 != NULL)
1646 		error (0, 0,
1647 		       "file %s has been modified, but has been removed in revision %s as of %s",
1648 		       finfo->fullname, jrev2, jdate2);
1649 	    else
1650 		error (0, 0,
1651 		       "file %s has been modified, but has been removed in revision %s",
1652 		       finfo->fullname, jrev2);
1653 
1654 	    /* FIXME: Should we arrange to return a non-zero exit
1655                status?  */
1656 
1657 	    if (rev1 != NULL)
1658 		free (rev1);
1659 
1660 	    return;
1661 	}
1662 
1663 	if (rev1 != NULL)
1664 	    free (rev1);
1665 
1666 	/* The user file exists and has not been modified.  Mark it
1667            for removal.  FIXME: If we are doing a checkout, this has
1668            the effect of first checking out the file, and then
1669            removing it.  It would be better to just register the
1670            removal.  */
1671 #ifdef SERVER_SUPPORT
1672 	if (server_active)
1673 	{
1674 	    server_scratch (finfo->file);
1675 	    server_updated (finfo, vers, SERVER_UPDATED, (struct stat *) NULL,
1676 			    (unsigned char *) NULL);
1677 	}
1678 #endif
1679 	mrev = xmalloc (strlen (vers->vn_user) + 2);
1680 	sprintf (mrev, "-%s", vers->vn_user);
1681 	Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
1682 		  vers->options, vers->tag, vers->date, vers->ts_conflict);
1683 	free (mrev);
1684 	/* We need to check existence_error here because if we are
1685            running as the server, and the file is up to date in the
1686            working directory, the client will not have sent us a copy.  */
1687 	if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1688 	    error (0, errno, "cannot remove file %s", finfo->fullname);
1689 #ifdef SERVER_SUPPORT
1690 	if (server_active)
1691 	    server_checked_in (finfo->file, finfo->update_dir,
1692 			       finfo->repository);
1693 #endif
1694 	if (! really_quiet)
1695 	    error (0, 0, "scheduling %s for removal", finfo->fullname);
1696 
1697 	return;
1698     }
1699 
1700     /* If the target of the merge is the same as the working file
1701        revision, then there is nothing to do.  */
1702     if (vers->vn_user != NULL && strcmp (rev2, vers->vn_user) == 0)
1703     {
1704 	if (rev1 != NULL)
1705 	    free (rev1);
1706 	free (rev2);
1707 	return;
1708     }
1709 
1710     /* If rev1 is dead or does not exist, then the file was added
1711        between rev1 and rev2.  */
1712     if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
1713     {
1714 	if (rev1 != NULL)
1715 	    free (rev1);
1716 	free (rev2);
1717 
1718 	/* If the file does not exist in the working directory, then
1719            we can just check out the new revision and mark it for
1720            addition.  */
1721 	if (vers->vn_user == NULL)
1722 	{
1723 	    Vers_TS *xvers;
1724 
1725 	    xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
1726 
1727 	    /* FIXME: If checkout_file fails, we should arrange to
1728                return a non-zero exit status.  */
1729 	    status = checkout_file (finfo, xvers, 1);
1730 
1731 #ifdef SERVER_SUPPORT
1732 	    if (server_active && status == 0)
1733 		server_updated (finfo, xvers,
1734 				SERVER_UPDATED, (struct stat *) NULL,
1735 				(unsigned char *) NULL);
1736 #endif
1737 
1738 	    freevers_ts (&xvers);
1739 
1740 	    return;
1741 	}
1742 
1743 	/* The file currently exists in the working directory, so we
1744            have a conflict which we can not resolve.  Note that this
1745            is true even if the file is marked for addition or removal.  */
1746 
1747 	if (jdate2 != NULL)
1748 	    error (0, 0,
1749 		   "file %s exists, but has been added in revision %s as of %s",
1750 		   finfo->fullname, jrev2, jdate2);
1751 	else
1752 	    error (0, 0,
1753 		   "file %s exists, but has been added in revision %s",
1754 		   finfo->fullname, jrev2);
1755 
1756 	return;
1757     }
1758 
1759     /* If the two merge revisions are the same, then there is nothing
1760        to do.  */
1761     if (strcmp (rev1, rev2) == 0)
1762     {
1763 	free (rev1);
1764 	free (rev2);
1765 	return;
1766     }
1767 
1768     /* If there is no working file, then we can't do the merge.  */
1769     if (vers->vn_user == NULL)
1770     {
1771 	free (rev1);
1772 	free (rev2);
1773 
1774 	if (jdate2 != NULL)
1775 	    error (0, 0,
1776 		   "file %s is present in revision %s as of %s",
1777 		   finfo->fullname, jrev2, jdate2);
1778 	else
1779 	    error (0, 0,
1780 		   "file %s is present in revision %s",
1781 		   finfo->fullname, jrev2);
1782 
1783 	/* FIXME: Should we arrange to return a non-zero exit status?  */
1784 
1785 	return;
1786     }
1787 
1788 #ifdef SERVER_SUPPORT
1789     if (server_active && !isreadable (finfo->file))
1790     {
1791 	int retcode;
1792 	/* The file is up to date.  Need to check out the current contents.  */
1793 	retcode = RCS_checkout (vers->srcfile, finfo->file,
1794 				vers->vn_user, (char *) NULL,
1795 				(char *) NULL, RUN_TTY);
1796 	if (retcode != 0)
1797 	    error (1, retcode == -1 ? errno : 0,
1798 		   "failed to check out %s file", finfo->fullname);
1799     }
1800 #endif
1801 
1802     /*
1803      * The users currently modified file is moved to a backup file name
1804      * ".#filename.version", so that it will stay around for a few days
1805      * before being automatically removed by some cron daemon.  The "version"
1806      * is the version of the file that the user was most up-to-date with
1807      * before the merge.
1808      */
1809     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1810 
1811     (void) unlink_file (backup);
1812     copy_file (finfo->file, backup);
1813     xchmod (finfo->file, 1);
1814 
1815     options = vers->options;
1816 #ifdef HAVE_RCS5
1817 #if 0
1818     if (*options == '\0')
1819 	options = "-kk";		/* to ignore keyword expansions */
1820 #endif
1821 #endif
1822 
1823     status = RCS_merge (vers->srcfile->path, options, rev1, rev2);
1824     if (status != 0 && status != 1)
1825     {
1826 	error (0, status == -1 ? errno : 0,
1827 	       "could not merge revision %s of %s", rev2, finfo->fullname);
1828 	error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
1829 	       finfo->fullname, backup);
1830 	rename_file (backup, finfo->file);
1831     }
1832     free (rev1);
1833     free (rev2);
1834 
1835 #ifdef SERVER_SUPPORT
1836     /*
1837      * If we're in server mode, then we need to re-register the file
1838      * even if there were no conflicts (status == 0).
1839      * This tells server_updated() to send the modified file back to
1840      * the client.
1841      */
1842     if (status == 1 || (status == 0 && server_active))
1843 #else
1844     if (status == 1)
1845 #endif
1846     {
1847 	char *cp = 0;
1848 
1849 	if (status)
1850 	    cp = time_stamp (finfo->file);
1851 	Register (finfo->entries, finfo->file,
1852 		  vers->vn_rcs, vers->ts_rcs, vers->options,
1853 		  vers->tag, vers->date, cp);
1854 	if (cp)
1855 	    free(cp);
1856     }
1857 
1858 #ifdef SERVER_SUPPORT
1859     if (server_active)
1860     {
1861 	server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
1862 			  backup);
1863 	server_updated (finfo, vers, SERVER_MERGED,
1864 			(struct stat *) NULL, (unsigned char *) NULL);
1865     }
1866 #endif
1867 }
1868 
1869 int
1870 joining ()
1871 {
1872     return (join_rev1 != NULL);
1873 }
1874