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