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