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