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