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