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