2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
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.
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.
12 * The present version can be committed by "commit", but this keeps the version
15 * Arguments following the options are taken to be file names to be updated,
16 * rather than updating the entire directory.
18 * Modified or non-existent RCS files are checked out and reported as U
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.
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>.
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
48 static int checkout_file (struct file_info *finfo, Vers_TS *vers_ts,
49 int adding, int merging, int update_server);
51 static void checkout_to_buffer (void *, const char *, size_t);
52 static int patch_file (struct file_info *finfo,
54 int *docheckout, struct stat *file_info,
55 unsigned char *checksum);
56 static void patch_file_write (void *, const char *, size_t);
58 static int merge_file (struct file_info *finfo, Vers_TS *vers);
59 static int scratch_file (struct file_info *finfo, Vers_TS *vers);
60 static Dtype update_dirent_proc (void *callerdat, const char *dir,
61 const char *repository,
62 const char *update_dir,
64 static int update_dirleave_proc (void *callerdat, const char *dir,
65 int err, const char *update_dir,
67 static int update_fileproc (void *callerdat, struct file_info *);
68 static int update_filesdone_proc (void *callerdat, int err,
69 const char *repository,
70 const char *update_dir, List *entries);
71 #ifdef PRESERVE_PERMISSIONS_SUPPORT
72 static int get_linkinfo_proc( void *_callerdat, struct _finfo * );
74 static void join_file (struct file_info *finfo, Vers_TS *vers_ts);
76 static char *options = NULL;
77 static char *tag = NULL;
78 static char *date = NULL;
79 /* This is a bit of a kludge. We call WriteTag at the beginning
80 before we know whether nonbranch is set or not. And then at the
81 end, once we have the right value for nonbranch, we call WriteTag
82 again. I don't know whether the first call is necessary or not.
83 rewrite_tag is nonzero if we are going to have to make that second
84 call. warned is nonzero if we've already warned the user that the
85 tag occurs as both a revision tag and a branch tag. */
86 static int rewrite_tag;
90 /* If we set the tag or date for a subdirectory, we use this to undo
91 the setting. See update_dirent_proc. */
92 static char *tag_update_dir;
94 static char *join_rev1, *date_rev1;
95 static char *join_rev2, *date_rev2;
97 static int toss_local_changes = 0;
98 static int force_tag_match = 1;
99 static int update_build_dirs = 0;
100 static int update_prune_dirs = 0;
101 static int pipeout = 0;
102 static int dotemplate = 0;
103 #ifdef SERVER_SUPPORT
104 static int patches = 0;
105 static int rcs_diff_patches = 0;
107 static List *ignlist = (List *) NULL;
108 static time_t last_register_time;
109 static const char *const update_usage[] =
111 "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n",
112 " [-I ign] [-W spec] [files...]\n",
113 "\t-A\tReset any sticky tags/date/kopts.\n",
114 "\t-P\tPrune empty directories.\n",
115 "\t-C\tOverwrite locally modified files with clean repository copies.\n",
116 "\t-d\tBuild directories, like checkout does.\n",
117 "\t-f\tForce a head revision match if tag/date not found.\n",
118 "\t-l\tLocal directory only, no recursion.\n",
119 "\t-R\tProcess directories recursively.\n",
120 "\t-p\tSend updates to standard output (avoids stickiness).\n",
121 "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
122 "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
123 "\t-D date\tSet date to update from (is sticky).\n",
124 "\t-j rev\tMerge in changes made between current revision and rev.\n",
125 "\t-I ign\tMore files to ignore (! to reset).\n",
126 "\t-W spec\tWrappers specification line.\n",
127 "(Specify the --help global option for a list of other help options)\n",
134 * update is the argv,argc based front end for arg parsing
137 update (int argc, char **argv)
140 int local = 0; /* recursive by default */
141 int which; /* where to look for files and dirs */
144 usage (update_usage);
151 while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1)
159 toss_local_changes = 1;
165 wrap_add (optarg, 0);
170 options = RCS_check_kflag (optarg);
180 #ifdef SERVER_SUPPORT
181 /* The CVS 1.5 client sends these options (in addition to
182 Global_option requests), so we must ignore them. */
186 "-q or -Q must be specified before \"%s\"",
190 update_build_dirs = 1;
199 date = Make_Date (optarg);
202 update_prune_dirs = 1;
206 noexec = 1; /* so no locks will be created */
210 error (1, 0, "only two -j options can be specified");
217 #ifdef SERVER_SUPPORT
221 rcs_diff_patches = server_use_rcs_diff ();
225 usage (update_usage);
229 usage (update_usage);
236 #ifdef CLIENT_SUPPORT
237 if (current_parsed_root->isremote)
241 /* The first pass does the regular update. If we receive at least
242 one patch which failed, we do a second pass and just fetch
243 those files whose patches failed. */
253 if (update_build_dirs)
257 if (!force_tag_match)
261 if (toss_local_changes)
263 if (update_prune_dirs)
265 client_prune_dirs = update_prune_dirs;
266 option_with_arg ("-r", tag);
267 if (options && options[0] != '\0')
270 client_senddate (date);
272 option_with_arg ("-j", join_rev1);
274 option_with_arg ("-j", join_rev2);
277 if (failed_patches_count == 0)
279 unsigned int flags = 0;
281 /* If the server supports the command "update-patches", that
282 means that it knows how to handle the -u argument to update,
283 which means to send patches instead of complete files.
285 We don't send -u if failed_patches != NULL, so that the
286 server doesn't try to send patches which will just fail
287 again. At least currently, the client also clobbers the
288 file and tells the server it is lost, which also will get
289 a full file instead of a patch, but it seems clean to omit
291 if (supported_request ("update-patches"))
296 if (update_build_dirs)
297 flags |= SEND_BUILD_DIRS;
299 if (toss_local_changes) {
300 flags |= SEND_NO_CONTENTS;
301 flags |= BACKUP_MODIFIED_FILES;
304 /* If noexec, probably could be setting SEND_NO_CONTENTS.
305 Same caveats as for "cvs status" apply. */
307 send_files (argc, argv, local, aflag, flags);
308 send_file_names (argc, argv, SEND_EXPAND_WILD);
314 (void) printf ("%s client: refetching unpatchable files\n",
317 if (toplevel_wd != NULL
318 && CVS_CHDIR (toplevel_wd) < 0)
320 error (1, errno, "could not chdir to %s", toplevel_wd);
325 for (i = 0; i < failed_patches_count; i++)
326 if (unlink_file (failed_patches[i]) < 0
327 && !existence_error (errno))
328 error (0, errno, "cannot remove %s",
330 send_files (failed_patches_count, failed_patches, local,
331 aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
332 send_file_names (failed_patches_count, failed_patches, 0);
333 free_names (&failed_patches_count, failed_patches);
336 send_to_server ("update\012", 0);
338 status = get_responses_and_close ();
340 /* If there are any conflicts, the server will return a
341 non-zero exit status. If any patches failed, we still
342 want to run the update again. We use a pass count to
343 avoid an endless loop. */
345 /* Notes: (1) assuming that status != 0 implies a
346 potential conflict is the best we can cleanly do given
347 the current protocol. I suppose that trying to
348 re-fetch in cases where there was a more serious error
349 is probably more or less harmless, but it isn't really
350 ideal. (2) it would be nice to have a testsuite case for the
351 conflict-and-patch-failed case. */
354 && (failed_patches_count == 0 || pass > 1))
356 if (failed_patches_count > 0)
357 free_names (&failed_patches_count, failed_patches);
362 } while (failed_patches_count > 0);
369 tag_check_valid (tag, argc, argv, local, aflag, "");
370 if (join_rev1 != NULL)
371 tag_check_valid_join (join_rev1, argc, argv, local, aflag, "");
372 if (join_rev2 != NULL)
373 tag_check_valid_join (join_rev2, argc, argv, local, aflag, "");
376 * If we are updating the entire directory (for real) and building dirs
377 * as we go, we make sure there is no static entries file and write the
378 * tag file as appropriate
380 if (argc <= 0 && !pipeout)
382 if (update_build_dirs)
384 if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
385 error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
386 #ifdef SERVER_SUPPORT
389 char *repos = Name_Repository (NULL, NULL);
390 server_clear_entstat (".", repos);
396 /* keep the CVS/Tag file current with the specified arguments */
397 if (aflag || tag || date)
399 char *repos = Name_Repository (NULL, NULL);
400 WriteTag (NULL, tag, date, 0, ".", repos);
408 /* look for files/dirs locally and in the repository */
409 which = W_LOCAL | W_REPOS;
411 /* look in the attic too if a tag or date is specified */
412 if (tag != NULL || date != NULL || joining())
415 /* call the command line interface */
416 err = do_update (argc, argv, options, tag, date, force_tag_match,
417 local, update_build_dirs, aflag, update_prune_dirs,
418 pipeout, which, join_rev1, join_rev2, NULL, 1, NULL);
420 /* free the space Make_Date allocated if necessary */
430 * Command line interface to update (used by checkout)
432 * repository = cvsroot->repository + update_dir. This is necessary for
433 * checkout so that start_recursion can determine our repository. In the
434 * update case, start_recursion can use the CVS/Root & CVS/Repository file
435 * to determine this value.
438 do_update (int argc, char **argv, char *xoptions, char *xtag, char *xdate,
439 int xforce, int local, int xbuild, int xaflag, int xprune,
440 int xpipeout, int which, char *xjoin_rev1, char *xjoin_rev2,
441 char *preload_update_dir, int xdotemplate, char *repository)
446 /* fill in the statics */
450 force_tag_match = xforce;
451 update_build_dirs = xbuild;
453 update_prune_dirs = xprune;
455 dotemplate = xdotemplate;
457 /* setup the join support */
458 join_rev1 = xjoin_rev1;
459 join_rev2 = xjoin_rev2;
460 if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
463 date_rev1 = Make_Date (cp);
467 if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
470 date_rev2 = Make_Date (cp);
475 #ifdef PRESERVE_PERMISSIONS_SUPPORT
478 /* We need to do an extra recursion, bleah. It's to make sure
479 that we know as much as possible about file linkage. */
480 hardlist = getlist();
481 working_dir = xgetwd(); /* save top-level working dir */
483 /* FIXME-twp: the arguments to start_recursion make me dizzy. This
484 function call was copied from the update_fileproc call that
485 follows it; someone should make sure that I did it right. */
486 err = start_recursion
487 (get_linkinfo_proc, NULL, NULL, NULL, NULL,
488 argc, argv, local, which, aflag, CVS_LOCK_READ,
489 preload_update_dir, 1, NULL);
493 /* FIXME-twp: at this point we should walk the hardlist
494 and update the `links' field of each hardlink_info struct
495 to list the files that are linked on dist. That would make
496 it easier & more efficient to compare the disk linkage with
497 the repository linkage (a simple strcmp). */
501 /* call the recursion processor */
502 err = start_recursion (update_fileproc, update_filesdone_proc,
503 update_dirent_proc, update_dirleave_proc, NULL,
504 argc, argv, local, which, aflag, CVS_LOCK_READ,
505 preload_update_dir, 1, repository);
507 #ifdef SERVER_SUPPORT
512 /* see if we need to sleep before returning to avoid time-stamp races */
513 if (last_register_time)
515 sleep_past (last_register_time);
523 #ifdef PRESERVE_PERMISSIONS_SUPPORT
525 * The get_linkinfo_proc callback adds each file to the hardlist
530 get_linkinfo_proc( void *callerdat, struct file_info *finfo )
534 struct hardlink_info *hlinfo;
536 /* Get the full pathname of the current file. */
537 fullpath = xmalloc (strlen(working_dir) +
538 strlen(finfo->fullname) + 2);
539 sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
541 /* To permit recursing into subdirectories, files
542 are keyed on the full pathname and not on the basename. */
543 linkp = lookup_file_by_inode (fullpath);
546 /* The file isn't on disk; we are probably restoring
547 a file that was removed. */
551 /* Create a new, empty hardlink_info node. */
552 hlinfo = (struct hardlink_info *)
553 xmalloc (sizeof (struct hardlink_info));
555 hlinfo->status = (Ctype) 0; /* is this dumb? */
556 hlinfo->checked_out = 0;
558 linkp->data = hlinfo;
567 * This is the callback proc for update. It is called for each file in each
568 * directory by the recursion code. The current directory is the local
569 * instantiation. file is the file name we are to operate on. update_dir is
570 * set to the path relative to where we started (for pretty printing).
571 * repository is the repository. entries and srcfiles are the pre-parsed
572 * entries and source control files.
574 * This routine decides what needs to be done for each file and does the
575 * appropriate magic for checkout
578 update_fileproc (void *callerdat, struct file_info *finfo)
584 status = Classify_File (finfo, tag, date, options, force_tag_match,
585 aflag, &vers, pipeout);
587 /* Keep track of whether TAG is a branch tag.
588 Note that if it is a branch tag in some files and a nonbranch tag
589 in others, treat it as a nonbranch tag. */
592 && finfo->rcs != NULL)
594 char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
596 && nonbranch != (nb = !RCS_nodeisbranch (finfo->rcs, tag)))
598 if (nonbranch >= 0 && !warned && !quiet)
601 "warning: %s is a branch tag in some files and a revision tag in others.",
605 if (nonbranch < nb) nonbranch = nb;
614 * We just return success without doing anything if any of the really
617 * If there is still a valid RCS file, do a regular checkout type
622 case T_UNKNOWN: /* unknown file was explicitly asked
624 case T_REMOVE_ENTRY: /* needs to be un-registered */
625 case T_ADDED: /* added but not committed */
628 case T_CONFLICT: /* old punt-type errors */
631 case T_UPTODATE: /* file was already up-to-date */
632 case T_NEEDS_MERGE: /* needs merging */
633 case T_MODIFIED: /* locally modified */
634 case T_REMOVED: /* removed but not committed */
635 case T_CHECKOUT: /* needs checkout */
636 case T_PATCH: /* needs patch */
637 retval = checkout_file (finfo, vers, 0, 0, 0);
640 default: /* can't ever happen :-) */
642 "unknown file status %d for file %s", status, finfo->file);
651 case T_UNKNOWN: /* unknown file was explicitly asked
653 case T_UPTODATE: /* file was already up-to-date */
656 case T_CONFLICT: /* old punt-type errors */
658 write_letter (finfo, 'C');
660 case T_NEEDS_MERGE: /* needs merging */
661 if (! toss_local_changes)
663 retval = merge_file (finfo, vers);
666 /* else FALL THROUGH */
667 case T_MODIFIED: /* locally modified */
669 if (toss_local_changes)
672 bakname = backup_file (finfo->file, vers->vn_user);
673 /* This behavior is sufficiently unexpected to
674 justify overinformativeness, I think. */
675 #ifdef SERVER_SUPPORT
676 if ((! really_quiet) && (! server_active))
677 #else /* ! SERVER_SUPPORT */
679 #endif /* SERVER_SUPPORT */
680 (void) printf ("(Locally modified %s moved to %s)\n",
681 finfo->file, bakname);
684 /* The locally modified file is still present, but
685 it will be overwritten by the repository copy
688 retval = checkout_file (finfo, vers, 0, 0, 1);
692 if (vers->ts_conflict)
694 if (file_has_conflict (finfo, vers->ts_conflict)
695 || file_has_markers (finfo))
697 write_letter (finfo, 'C');
702 /* Reregister to clear conflict flag. */
703 Register (finfo->entries, finfo->file,
704 vers->vn_rcs, vers->ts_rcs,
705 vers->options, vers->tag,
706 vers->date, (char *)0);
710 write_letter (finfo, 'M');
713 case T_PATCH: /* needs patch */
714 #ifdef SERVER_SUPPORT
718 struct stat file_info;
719 unsigned char checksum[16];
721 retval = patch_file (finfo,
723 &file_info, checksum);
726 if (server_active && retval == 0)
727 server_updated (finfo, vers,
731 file_info.st_mode, checksum,
732 (struct buffer *) NULL);
737 /* If we're not running as a server, just check the
738 file out. It's simpler and faster than producing
739 and applying patches. */
741 case T_CHECKOUT: /* needs checkout */
742 retval = checkout_file (finfo, vers, 0, 0, 1);
744 case T_ADDED: /* added but not committed */
745 write_letter (finfo, 'A');
748 case T_REMOVED: /* removed but not committed */
749 write_letter (finfo, 'R');
752 case T_REMOVE_ENTRY: /* needs to be un-registered */
753 retval = scratch_file (finfo, vers);
755 default: /* can't ever happen :-) */
757 "unknown file status %d for file %s", status, finfo->file);
763 /* only try to join if things have gone well thus far */
764 if (retval == 0 && join_rev1)
765 join_file (finfo, vers);
767 /* if this directory has an ignore list, add this file to it */
768 if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
774 p->key = xstrdup (finfo->file);
775 if (addnode (ignlist, p) != 0)
786 update_ignproc (const char *file, const char *dir)
788 struct file_info finfo;
791 memset (&finfo, 0, sizeof (finfo));
793 finfo.update_dir = dir;
795 tmp = xstrdup (file);
798 tmp = xmalloc (strlen (file) + strlen (dir) + 10);
804 finfo.fullname = tmp;
805 write_letter (&finfo, '?');
813 update_filesdone_proc (void *callerdat, int err, const char *repository,
814 const char *update_dir, List *entries)
816 if (nonbranch < 0) nonbranch = 0;
819 WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
823 /* if this directory has an ignore list, process it then free it */
826 ignore_files (ignlist, entries, update_dir, update_ignproc);
830 /* Clean up CVS admin dirs if we are export */
831 if (strcmp (cvs_cmd_name, "export") == 0)
833 /* I'm not sure the existence_error is actually possible (except
834 in cases where we really should print a message), but since
835 this code used to ignore all errors, I'll play it safe. */
836 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
837 error (0, errno, "cannot remove %s directory", CVSADM);
839 #ifdef SERVER_SUPPORT
840 else if (!server_active && !pipeout)
843 #endif /* SERVER_SUPPORT */
845 /* If there is no CVS/Root file, add one */
846 if (!isfile (CVSADM_ROOT))
847 Create_Root (NULL, current_parsed_root->original);
856 * update_dirent_proc () is called back by the recursion processor before a
857 * sub-directory is processed for update. In this case, update_dirent proc
858 * will probably create the directory unless -d isn't specified and this is a
859 * new directory. A return code of 0 indicates the directory should be
860 * processed by the recursion code. A return of non-zero indicates the
861 * recursion code should skip this directory.
864 update_dirent_proc (void *callerdat, const char *dir, const char *repository,
865 const char *update_dir, List *entries)
867 if (ignore_directory (update_dir))
869 /* print the warm fuzzy message */
871 error (0, 0, "Ignoring %s", update_dir);
877 /* if we aren't building dirs, blow it off */
878 if (!update_build_dirs)
881 /* Various CVS administrators are in the habit of removing
882 the repository directory for things they don't want any
883 more. I've even been known to do it myself (on rare
884 occasions). Not the usual recommended practice, but we
885 want to try to come up with some kind of
886 reasonable/documented/sensible behavior. Generally
887 the behavior is to just skip over that directory (see
888 dirs test in sanity.sh; the case which reaches here
889 is when update -d is specified, and the working directory
890 is gone but the subdirectory is still mentioned in
893 #ifdef SERVER_SUPPORT
894 /* In the remote case, the client should refrain from
895 sending us the directory in the first place. So we
896 want to continue to give an error, so clients make
900 && !isdir (repository))
905 /* ignore the missing dir if -n is specified */
906 error (0, 0, "New directory `%s' -- ignored", update_dir);
911 /* otherwise, create the dir and appropriate adm files */
913 /* If no tag or date were specified on the command line,
914 and we're not using -A, we want the subdirectory to use
915 the tag and date, if any, of the current directory.
916 That way, update -d will work correctly when working on
919 We use TAG_UPDATE_DIR to undo the tag setting in
920 update_dirleave_proc. If we did not do this, we would
921 not correctly handle a working directory with multiple
922 tags (and maybe we should prohibit such working
923 directories, but they work now and we shouldn't make
924 them stop working without more thought). */
925 if ((tag == NULL && date == NULL) && ! aflag)
927 ParseTag (&tag, &date, &nonbranch);
928 if (tag != NULL || date != NULL)
929 tag_update_dir = xstrdup (update_dir);
932 make_directory (dir);
933 Create_Admin (dir, update_dir, repository, tag, date,
934 /* This is a guess. We will rewrite it later
942 Subdir_Register (entries, NULL, dir);
945 /* Do we need to check noexec here? */
950 /* The directory exists. Check to see if it has a CVS
953 cvsadmdir = xmalloc (strlen (dir) + 80);
954 strcpy (cvsadmdir, dir);
955 strcat (cvsadmdir, "/");
956 strcat (cvsadmdir, CVSADM);
958 if (!isdir (cvsadmdir))
960 /* We cannot successfully recurse into a directory without a CVS
961 subdirectory. Generally we will have already printed
970 * If we are building dirs and not going to stdout, we make sure there is
971 * no static entries file and write the tag file as appropriate
975 if (update_build_dirs)
979 tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10);
980 (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
981 if (unlink_file (tmp) < 0 && ! existence_error (errno))
982 error (1, errno, "cannot remove file %s", tmp);
983 #ifdef SERVER_SUPPORT
985 server_clear_entstat (update_dir, repository);
990 /* keep the CVS/Tag file current with the specified arguments */
991 if (aflag || tag || date)
993 WriteTag (dir, tag, date, 0, update_dir, repository);
999 WriteTemplate (update_dir, dotemplate, repository);
1001 /* initialize the ignore list for this directory */
1002 ignlist = getlist ();
1005 /* print the warm fuzzy message */
1007 error (0, 0, "Updating %s", update_dir);
1015 * update_dirleave_proc () is called back by the recursion code upon leaving
1016 * a directory. It will prune empty directories if needed and will execute
1017 * any appropriate update programs.
1021 update_dirleave_proc (void *callerdat, const char *dir, int err,
1022 const char *update_dir, List *entries)
1024 /* Delete the ignore list if it hasn't already been done. */
1028 /* If we set the tag or date for a new subdirectory in
1029 update_dirent_proc, and we're now done with that subdirectory,
1030 undo the tag/date setting. Note that we know that the tag and
1031 date were both originally NULL in this case. */
1032 if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
1046 free (tag_update_dir);
1047 tag_update_dir = NULL;
1050 if (strchr (dir, '/') == NULL)
1052 /* FIXME: chdir ("..") loses with symlinks. */
1053 /* Prune empty dirs on the way out - if necessary */
1054 (void) CVS_CHDIR ("..");
1055 if (update_prune_dirs && isemptydir (dir, 0))
1057 /* I'm not sure the existence_error is actually possible (except
1058 in cases where we really should print a message), but since
1059 this code used to ignore all errors, I'll play it safe. */
1060 if (unlink_file_dir (dir) < 0 && !existence_error (errno))
1061 error (0, errno, "cannot remove %s directory", dir);
1062 Subdir_Deregister (entries, NULL, dir);
1071 /* Returns 1 if the file indicated by node has been removed. */
1073 isremoved (Node *node, void *closure)
1075 Entnode *entdata = node->data;
1077 /* If the first character of the version is a '-', the file has been
1079 return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
1084 /* Returns 1 if the argument directory is completely empty, other than the
1085 existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
1086 and the directory doesn't exist, then just return 0. */
1088 isemptydir (const char *dir, int might_not_exist)
1093 if ((dirp = CVS_OPENDIR (dir)) == NULL)
1095 if (might_not_exist && existence_error (errno))
1097 error (0, errno, "cannot open directory %s for empty check", dir);
1101 while ((dp = CVS_READDIR (dirp)) != NULL)
1103 if (strcmp (dp->d_name, ".") != 0
1104 && strcmp (dp->d_name, "..") != 0)
1106 if (strcmp (dp->d_name, CVSADM) != 0)
1108 /* An entry other than the CVS directory. The directory
1109 is certainly not empty. */
1110 (void) CVS_CLOSEDIR (dirp);
1115 /* The CVS directory entry. We don't have to worry about
1116 this unless the Entries file indicates that files have
1117 been removed, but not committed, in this directory.
1118 (Removing the directory would prevent people from
1119 comitting the fact that they removed the files!) */
1122 struct saved_cwd cwd;
1124 if (save_cwd (&cwd))
1125 exit (EXIT_FAILURE);
1127 if (CVS_CHDIR (dir) < 0)
1128 error (1, errno, "cannot change directory to %s", dir);
1129 l = Entries_Open (0, NULL);
1130 files_removed = walklist (l, isremoved, 0);
1133 if (restore_cwd (&cwd, NULL))
1134 exit (EXIT_FAILURE);
1137 if (files_removed != 0)
1139 /* There are files that have been removed, but not
1140 committed! Do not consider the directory empty. */
1141 (void) CVS_CLOSEDIR (dirp);
1150 error (0, errno, "cannot read directory %s", dir);
1151 (void) CVS_CLOSEDIR (dirp);
1154 (void) CVS_CLOSEDIR (dirp);
1161 * scratch the Entries file entry associated with a file
1164 scratch_file (struct file_info *finfo, Vers_TS *vers)
1166 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
1167 Scratch_Entry (finfo->entries, finfo->file);
1168 #ifdef SERVER_SUPPORT
1171 if (vers->ts_user == NULL)
1172 server_scratch_entry_only ();
1173 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1, NULL, NULL);
1176 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1177 error (0, errno, "unable to remove %s", finfo->fullname);
1179 #ifdef SERVER_SUPPORT
1180 /* skip this step when the server is running since
1181 * server_updated should have handled it */
1185 /* keep the vers structure up to date in case we do a join
1186 * - if there isn't a file, it can't very well have a version number, can it?
1188 if (vers->vn_user != NULL)
1190 free (vers->vn_user);
1191 vers->vn_user = NULL;
1193 if (vers->ts_user != NULL)
1195 free (vers->ts_user);
1196 vers->ts_user = NULL;
1208 checkout_file (struct file_info *finfo, Vers_TS *vers_ts, int adding,
1209 int merging, int update_server)
1212 int set_time, retval = 0;
1215 struct buffer *revbuf;
1220 /* Don't screw with backup files if we're going to stdout, or if
1221 we are the server. */
1223 #ifdef SERVER_SUPPORT
1228 backup = xmalloc (strlen (finfo->file)
1230 + sizeof (CVSPREFIX)
1232 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1233 if (isfile (finfo->file))
1234 rename_file (finfo->file, backup);
1237 /* If -f/-t wrappers are being used to wrap up a directory,
1238 then backup might be a directory instead of just a file. */
1239 if (unlink_file_dir (backup) < 0)
1241 /* Not sure if the existence_error check is needed here. */
1242 if (!existence_error (errno))
1243 /* FIXME: should include update_dir in message. */
1244 error (0, errno, "error removing %s", backup);
1251 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
1256 * if we are checking out to stdout, print a nice message to
1257 * stderr, and add the -p flag to the command */
1263 ===================================================================\n\
1265 cvs_outerr (finfo->fullname, 0);
1268 cvs_outerr (vers_ts->srcfile->path, 0);
1271 cvs_outerr (vers_ts->vn_rcs, 0);
1272 cvs_outerr ("\n***************\n", 0);
1276 #ifdef SERVER_SUPPORT
1280 && ! file_gzip_level
1282 && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
1284 revbuf = buf_nonio_initialize (NULL);
1285 status = RCS_checkout (vers_ts->srcfile, NULL,
1286 vers_ts->vn_rcs, vers_ts->tag,
1287 vers_ts->options, RUN_TTY,
1288 checkout_to_buffer, revbuf);
1292 status = RCS_checkout (vers_ts->srcfile,
1293 pipeout ? NULL : finfo->file,
1294 vers_ts->vn_rcs, vers_ts->tag,
1295 vers_ts->options, RUN_TTY, NULL, NULL);
1297 if (file_is_dead || status == 0)
1307 if (revbuf != NULL && !noexec)
1311 /* FIXME: We should have RCS_checkout return the mode.
1312 That would also fix the kludge with noexec, above, which
1313 is here only because noexec doesn't write srcfile->path
1315 if( CVS_STAT( vers_ts->srcfile->path, &sb ) < 0 )
1318 error (1, errno, "cannot stat %s",
1319 vers_ts->srcfile->path);
1321 mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
1326 && !fileattr_get (finfo->file, "_watched"))
1329 xchmod (finfo->file, 1);
1332 /* We know that we are the server here, so
1333 although xchmod checks umask, we don't bother. */
1334 mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
1335 | ((mode & S_IRGRP) ? S_IWGRP : 0)
1336 | ((mode & S_IROTH) ? S_IWOTH : 0));
1341 /* A newly checked out file is never under the spell
1342 of "cvs edit". If we think we were editing it
1343 from a previous life, clean up. Would be better to
1344 check for same the working directory instead of
1345 same user, but that is hairy. */
1347 struct addremove_args args;
1349 editor_set (finfo->file, getcaller (), NULL);
1351 memset (&args, 0, sizeof args);
1352 args.remove_temp = 1;
1353 watch_modify_watchers (finfo->file, &args);
1356 /* set the time from the RCS file iff it was unknown before */
1359 && (vers_ts->vn_user == NULL ||
1360 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
1363 wrap_fromcvs_process_file (finfo->file);
1365 xvers_ts = Version_TS (finfo, options, tag, date,
1366 force_tag_match, set_time);
1367 if (strcmp (xvers_ts->options, "-V4") == 0)
1368 xvers_ts->options[0] = '\0';
1372 /* If we stored the file data into a buffer, then we
1373 didn't create a file at all, so xvers_ts->ts_user
1374 is wrong. The correct value is to have it be the
1375 same as xvers_ts->ts_rcs, meaning that the working
1376 file is unchanged from the RCS file.
1378 FIXME: We should tell Version_TS not to waste time
1379 statting the nonexistent file.
1381 FIXME: Actually, I don't think the ts_user value
1382 matters at all here. The only use I know of is
1383 that it is printed in a trace message by
1386 if (xvers_ts->ts_user != NULL)
1387 free (xvers_ts->ts_user);
1388 xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
1391 (void) time (&last_register_time);
1395 if (xvers_ts->vn_user != NULL)
1398 "warning: %s is not (any longer) pertinent",
1401 Scratch_Entry (finfo->entries, finfo->file);
1402 #ifdef SERVER_SUPPORT
1403 if (server_active && xvers_ts->ts_user == NULL)
1404 server_scratch_entry_only ();
1406 /* FIXME: Rather than always unlink'ing, and ignoring the
1407 existence_error, we should do the unlink only if
1408 vers_ts->ts_user is non-NULL. Then there would be no
1409 need to ignore an existence_error (for example, if the
1410 user removes the file while we are running). */
1411 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1413 error (0, errno, "cannot remove %s", finfo->fullname);
1417 Register (finfo->entries, finfo->file,
1418 adding ? "0" : xvers_ts->vn_rcs,
1419 xvers_ts->ts_user, xvers_ts->options,
1420 xvers_ts->tag, xvers_ts->date,
1421 NULL); /* Clear conflict flag on fresh checkout */
1423 /* fix up the vers structure, in case it is used by join */
1426 /* FIXME: Throwing away the original revision info is almost
1427 certainly wrong -- what if join_rev1 is "BASE"? */
1428 if (vers_ts->vn_user != NULL)
1429 free (vers_ts->vn_user);
1430 if (vers_ts->vn_rcs != NULL)
1431 free (vers_ts->vn_rcs);
1432 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1433 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1436 /* If this is really Update and not Checkout, recode history */
1437 if (strcmp (cvs_cmd_name, "update") == 0)
1438 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1441 freevers_ts (&xvers_ts);
1443 if (!really_quiet && !file_is_dead)
1445 write_letter (finfo, 'U');
1449 #ifdef SERVER_SUPPORT
1450 if (update_server && server_active)
1451 server_updated (finfo, vers_ts,
1452 merging ? SERVER_MERGED : SERVER_UPDATED,
1453 mode, (unsigned char *) NULL, revbuf);
1460 rename_file (backup, finfo->file);
1465 error (0, 0, "could not check out %s", finfo->fullname);
1472 /* If -f/-t wrappers are being used to wrap up a directory,
1473 then backup might be a directory instead of just a file. */
1474 if (unlink_file_dir (backup) < 0)
1476 /* Not sure if the existence_error check is needed here. */
1477 if (!existence_error (errno))
1478 /* FIXME: should include update_dir in message. */
1479 error (0, errno, "error removing %s", backup);
1491 #ifdef SERVER_SUPPORT
1493 /* This function is used to write data from a file being checked out
1497 checkout_to_buffer (void *callerdat, const char *data, size_t len)
1499 struct buffer *buf = (struct buffer *) callerdat;
1501 buf_output (buf, data, len);
1504 #endif /* SERVER_SUPPORT */
1506 #ifdef SERVER_SUPPORT
1508 /* This structure is used to pass information between patch_file and
1509 patch_file_write. */
1511 struct patch_file_data
1513 /* File name, for error messages. */
1514 const char *filename;
1515 /* File to which to write. */
1517 /* Whether to compute the MD5 checksum. */
1518 int compute_checksum;
1519 /* Data structure for computing the MD5 checksum. */
1520 struct cvs_MD5Context context;
1521 /* Set if the file has a final newline. */
1525 /* Patch a file. Runs diff. This is only done when running as the
1526 * server. The hope is that the diff will be smaller than the file
1530 patch_file (struct file_info *finfo, Vers_TS *vers_ts, int *docheckout, struct stat *file_info, unsigned char *checksum)
1539 struct patch_file_data data;
1543 if (noexec || pipeout || joining ())
1549 /* If this file has been marked as being binary, then never send a
1551 if (strcmp (vers_ts->options, "-kb") == 0)
1557 /* First check that the first revision exists. If it has been nuked
1558 by cvs admin -o, then just fall back to checking out entire
1559 revisions. In some sense maybe we don't have to do this; after
1560 all cvs.texinfo says "Make sure that no-one has checked out a
1561 copy of the revision you outdate" but then again, that advice
1562 doesn't really make complete sense, because "cvs admin" operates
1563 on a working directory and so _someone_ will almost always have
1564 _some_ revision checked out. */
1568 rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
1578 /* If the revision is dead, let checkout_file handle it rather
1579 than duplicating the processing here. */
1580 if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
1586 backup = xmalloc (strlen (finfo->file)
1588 + sizeof (CVSPREFIX)
1590 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1591 if (isfile (finfo->file))
1592 rename_file (finfo->file, backup);
1595 if (unlink_file (backup) < 0
1596 && !existence_error (errno))
1597 error (0, errno, "cannot remove %s", backup);
1600 file1 = xmalloc (strlen (finfo->file)
1602 + sizeof (CVSPREFIX)
1604 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1605 file2 = xmalloc (strlen (finfo->file)
1607 + sizeof (CVSPREFIX)
1609 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1613 /* We need to check out both revisions first, to see if either one
1614 has a trailing newline. Because of this, we don't use rcsdiff,
1615 but just use diff. */
1617 e = CVS_FOPEN (file1, "w");
1619 error (1, errno, "cannot open %s", file1);
1621 data.filename = file1;
1624 data.compute_checksum = 0;
1626 /* FIXME - Passing vers_ts->tag here is wrong in the least number
1627 * of cases. Since we don't know whether vn_user was checked out
1628 * using a tag, we pass vers_ts->tag, which, assuming the user did
1629 * not specify a new TAG to -r, will be the branch we are on.
1631 * The only thing it is used for is to substitute in for the Name
1632 * RCS keyword, so in the error case, the patch fails to apply on
1633 * the client end and we end up resending the whole file.
1635 * At least, if we are keeping track of the tag vn_user came from,
1636 * I don't know where yet. -DRP
1638 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1639 vers_ts->vn_user, vers_ts->tag,
1640 vers_ts->options, RUN_TTY,
1641 patch_file_write, (void *) &data);
1644 error (1, errno, "cannot close %s", file1);
1646 if (retcode != 0 || ! data.final_nl)
1651 e = CVS_FOPEN (file2, "w");
1653 error (1, errno, "cannot open %s", file2);
1655 data.filename = file2;
1658 data.compute_checksum = 1;
1659 cvs_MD5Init (&data.context);
1661 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1662 vers_ts->vn_rcs, vers_ts->tag,
1663 vers_ts->options, RUN_TTY,
1664 patch_file_write, (void *) &data);
1667 error (1, errno, "cannot close %s", file2);
1669 if (retcode != 0 || ! data.final_nl)
1672 cvs_MD5Final (checksum, &data.context);
1680 /* If the client does not support the Rcs-diff command, we
1681 send a context diff, and the client must invoke patch.
1682 That approach was problematical for various reasons. The
1683 new approach only requires running diff in the server; the
1684 client can handle everything without invoking an external
1686 if (! rcs_diff_patches)
1688 /* We use -c, not -u, because that is what CVS has
1689 traditionally used. Kind of a moot point, now that
1690 Rcs-diff is preferred, so there is no point in making
1691 the compatibility issues worse. */
1692 diff_options = "-c";
1696 /* Now that diff is librarified, we could be passing -a if
1697 we wanted to. However, it is unclear to me whether we
1698 would want to. Does diff -a, in any significant
1699 percentage of cases, produce patches which are smaller
1700 than the files it is patching? I guess maybe text
1701 files with character sets which diff regards as
1702 'binary'. Conversely, do they tend to be much larger
1703 in the bad cases? This needs some more
1704 thought/investigation, I suspect. */
1706 diff_options = "-n";
1708 retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file);
1710 /* A retcode of 0 means no differences. 1 means some differences. */
1720 struct stat file2_info;
1722 /* Check to make sure the patch is really shorter */
1723 if (CVS_STAT (file2, &file2_info) < 0)
1724 error (1, errno, "could not stat %s", file2);
1725 if (CVS_STAT (finfo->file, file_info) < 0)
1726 error (1, errno, "could not stat %s", finfo->file);
1727 if (file2_info.st_size <= file_info->st_size)
1733 # define BINARY "Binary"
1734 char buf[sizeof BINARY];
1737 /* Check the diff output to make sure patch will be handle it. */
1738 e = CVS_FOPEN (finfo->file, "r");
1740 error (1, errno, "could not open diff output file %s",
1742 c = fread (buf, 1, sizeof BINARY - 1, e);
1744 if (strcmp (buf, BINARY) == 0)
1746 /* These are binary files. We could use diff -a, but
1747 patch can't handle that. */
1757 /* Stat the original RCS file, and then adjust it the way
1758 that RCS_checkout would. FIXME: This is an abstraction
1760 if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0)
1761 error (1, errno, "could not stat %s", vers_ts->srcfile->path);
1762 if (chmod (finfo->file,
1763 file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
1765 error (0, errno, "cannot change mode of file %s", finfo->file);
1767 && !fileattr_get (finfo->file, "_watched"))
1768 xchmod (finfo->file, 1);
1770 /* This stuff is just copied blindly from checkout_file. I
1771 don't really know what it does. */
1772 xvers_ts = Version_TS (finfo, options, tag, date,
1773 force_tag_match, 0);
1774 if (strcmp (xvers_ts->options, "-V4") == 0)
1775 xvers_ts->options[0] = '\0';
1777 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1778 xvers_ts->ts_user, xvers_ts->options,
1779 xvers_ts->tag, xvers_ts->date, NULL);
1781 if (CVS_STAT (finfo->file, file_info) < 0)
1782 error (1, errno, "could not stat %s", finfo->file);
1784 /* If this is really Update and not Checkout, record history. */
1785 if (strcmp (cvs_cmd_name, "update") == 0)
1786 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
1787 finfo->file, finfo->repository);
1789 freevers_ts (&xvers_ts);
1793 write_letter (finfo, 'P');
1798 int old_errno = errno; /* save errno value over the rename */
1800 if (isfile (backup))
1801 rename_file (backup, finfo->file);
1803 if (retcode != 0 && retcode != 1)
1804 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1805 "could not diff %s", finfo->fullname);
1811 if (unlink_file (backup) < 0
1812 && !existence_error (errno))
1813 error (0, errno, "cannot remove %s", backup);
1814 if (unlink_file (file1) < 0
1815 && !existence_error (errno))
1816 error (0, errno, "cannot remove %s", file1);
1817 if (unlink_file (file2) < 0
1818 && !existence_error (errno))
1819 error (0, errno, "cannot remove %s", file2);
1829 /* Write data to a file. Record whether the last byte written was a
1830 newline. Optionally compute a checksum. This is called by
1831 patch_file via RCS_checkout. */
1834 patch_file_write (void *callerdat, const char *buffer, size_t len)
1836 struct patch_file_data *data = (struct patch_file_data *) callerdat;
1838 if (fwrite (buffer, 1, len, data->fp) != len)
1839 error (1, errno, "cannot write %s", data->filename);
1841 data->final_nl = (buffer[len - 1] == '\n');
1843 if (data->compute_checksum)
1844 cvs_MD5Update (&data->context, (unsigned char *) buffer, len);
1847 #endif /* SERVER_SUPPORT */
1850 * Several of the types we process only print a bit of information consisting
1851 * of a single letter and the name.
1854 write_letter (struct file_info *finfo, int letter)
1859 /* Big enough for "+updated" or any of its ilk. */
1868 /* We don't yet support tagged output except for "U". */
1874 sprintf (buf, "+%s", tag);
1875 cvs_output_tagged (buf, NULL);
1880 cvs_output_tagged ("text", buf);
1881 cvs_output_tagged ("fname", finfo->fullname);
1882 cvs_output_tagged ("newline", NULL);
1885 sprintf (buf, "-%s", tag);
1886 cvs_output_tagged (buf, NULL);
1895 * Do all the magic associated with a file which needs to be merged
1898 merge_file (struct file_info *finfo, Vers_TS *vers)
1905 * The users currently modified file is moved to a backup file name
1906 * ".#filename.version", so that it will stay around for a few days
1907 * before being automatically removed by some cron daemon. The "version"
1908 * is the version of the file that the user was most up-to-date with
1911 backup = xmalloc (strlen (finfo->file)
1912 + strlen (vers->vn_user)
1913 + sizeof (BAKPREFIX)
1915 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1917 if (unlink_file (backup) && !existence_error (errno))
1918 error (0, errno, "unable to remove %s", backup);
1919 copy_file (finfo->file, backup);
1920 xchmod (finfo->file, 1);
1922 if (strcmp (vers->options, "-kb") == 0
1923 || wrap_merge_is_copy (finfo->file)
1924 || special_file_mismatch (finfo, NULL, vers->vn_rcs))
1926 /* For binary files, a merge is always a conflict. Same for
1927 files whose permissions or linkage do not match. We give the
1928 user the two files, and let them resolve it. It is possible
1929 that we should require a "touch foo" or similar step before
1930 we allow a checkin. */
1932 /* TODO: it may not always be necessary to regard a permission
1933 mismatch as a conflict. The working file and the RCS file
1934 have a common ancestor `A'; if the working file's permissions
1935 match A's, then it's probably safe to overwrite them with the
1936 RCS permissions. Only if the working file, the RCS file, and
1937 A all disagree should this be considered a conflict. But more
1938 thought needs to go into this, and in the meantime it is safe
1939 to treat any such mismatch as an automatic conflict. -twp */
1941 #ifdef SERVER_SUPPORT
1943 server_copy_file (finfo->file, finfo->update_dir,
1944 finfo->repository, backup);
1947 status = checkout_file (finfo, vers, 0, 1, 1);
1949 /* Is there a better term than "nonmergeable file"? What we
1950 really mean is, not something that CVS cannot or does not
1951 want to merge (there might be an external manual or
1952 automatic merge process). */
1953 error (0, 0, "nonmergeable file needs merge");
1954 error (0, 0, "revision %s from repository is now in %s",
1955 vers->vn_rcs, finfo->fullname);
1956 error (0, 0, "file from working directory is now in %s", backup);
1957 write_letter (finfo, 'C');
1959 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
1965 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
1966 vers->options, vers->vn_user, vers->vn_rcs);
1967 if (status != 0 && status != 1)
1969 error (0, status == -1 ? errno : 0,
1970 "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
1971 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
1972 finfo->fullname, backup);
1973 rename_file (backup, finfo->file);
1978 if (strcmp (vers->options, "-V4") == 0)
1979 vers->options[0] = '\0';
1981 /* This file is the result of a merge, which means that it has
1982 been modified. We use a special timestamp string which will
1983 not compare equal to any actual timestamp. */
1989 (void) time (&last_register_time);
1990 cp = time_stamp (finfo->file);
1992 Register (finfo->entries, finfo->file, vers->vn_rcs,
1993 "Result of merge", vers->options, vers->tag,
1999 /* fix up the vers structure, in case it is used by join */
2002 /* FIXME: Throwing away the original revision info is almost
2003 certainly wrong -- what if join_rev1 is "BASE"? */
2004 if (vers->vn_user != NULL)
2005 free (vers->vn_user);
2006 vers->vn_user = xstrdup (vers->vn_rcs);
2009 #ifdef SERVER_SUPPORT
2010 /* Send the new contents of the file before the message. If we
2011 wanted to be totally correct, we would have the client write
2012 the message only after the file has safely been written. */
2015 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
2017 server_updated (finfo, vers, SERVER_MERGED,
2018 (mode_t) -1, (unsigned char *) NULL,
2019 (struct buffer *) NULL);
2025 error (0, 0, "conflicts found in %s", finfo->fullname);
2027 write_letter (finfo, 'C');
2029 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2033 else /* status == 0 */
2035 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2038 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2039 xcmp on the temporary files without much hassle, I think. */
2040 if (!noexec && !xcmp (backup, finfo->file))
2042 cvs_output (finfo->fullname, 0);
2043 cvs_output (" already contains the differences between ", 0);
2044 cvs_output (vers->vn_user, 0);
2045 cvs_output (" and ", 0);
2046 cvs_output (vers->vn_rcs, 0);
2047 cvs_output ("\n", 1);
2053 write_letter (finfo, 'M');
2064 * Do all the magic associated with a file which needs to be joined
2065 * (reached via the -j option to checkout or update).
2068 * finfo File information about the destination file.
2069 * vers The Vers_TS structure for finfo.
2072 * join_rev1 From the command line.
2073 * join_rev2 From the command line.
2074 * server_active Natch.
2077 * 1. Is not called in client mode.
2080 join_file (struct file_info *finfo, Vers_TS *vers)
2093 TRACE ( 1, "join_file(%s, %s%s%s%s, %s, %s)",
2095 vers->tag ? vers->tag : "",
2096 vers->tag ? " (" : "",
2097 vers->vn_rcs ? vers->vn_rcs : "",
2098 vers->tag ? ")" : "",
2099 join_rev1 ? join_rev1 : "",
2100 join_rev2 ? join_rev2 : "" );
2107 /* Determine if we need to do anything at all. */
2108 if (vers->srcfile == NULL ||
2109 vers->srcfile->path == NULL)
2114 /* If only one join revision is specified, it becomes the second
2124 /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
2125 below about vn_user. */
2127 /* Convert the second revision, walking branches and dates. */
2128 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
2130 /* If this is a merge of two revisions, get the first revision.
2131 If only one join tag was specified, then the first revision is
2132 the greatest common ancestor of the second revision and the
2135 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL);
2138 /* Note that we use vn_rcs here, since vn_user may contain a
2139 special string such as "-nn". */
2140 if (vers->vn_rcs == NULL)
2142 else if (rev2 == NULL)
2144 /* This means that the file never existed on the branch.
2145 It does not mean that the file was removed on the
2146 branch: that case is represented by a dead rev2. If
2147 the file never existed on the branch, then we have
2148 nothing to merge, so we just return. */
2152 rev1 = gca (vers->vn_rcs, rev2);
2155 /* Handle a nonexistent or dead merge target. */
2156 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
2163 /* If the first revision doesn't exist either, then there is
2164 no change between the two revisions, so we don't do
2166 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2173 /* If we are merging two revisions, then the file was removed
2174 between the first revision and the second one. In this
2175 case we want to mark the file for removal.
2177 If we are merging one revision, then the file has been
2178 removed between the greatest common ancestor and the merge
2179 revision. From the perspective of the branch on to which
2180 we ar emerging, which may be the trunk, either 1) the file
2181 does not currently exist on the target, or 2) the file has
2182 not been modified on the target branch since the greatest
2183 common ancestor, or 3) the file has been modified on the
2184 target branch since the greatest common ancestor. In case
2185 1 there is nothing to do. In case 2 we mark the file for
2186 removal. In case 3 we have a conflict.
2188 Note that the handling is slightly different depending upon
2189 whether one or two join targets were specified. If two
2190 join targets were specified, we don't check whether the
2191 file was modified since a given point. My reasoning is
2192 that if you ask for an explicit merge between two tags,
2193 then you want to merge in whatever was changed between
2194 those two tags. If a file was removed between the two
2195 tags, then you want it to be removed. However, if you ask
2196 for a merge of a branch, then you want to merge in all
2197 changes which were made on the branch. If a file was
2198 removed on the branch, that is a change to the file. If
2199 the file was also changed on the main line, then that is
2200 also a change. These two changes--the file removal and the
2201 modification--must be merged. This is a conflict. */
2203 /* If the user file is dead, or does not exist, or has been
2204 marked for removal, then there is nothing to do. */
2205 if (vers->vn_user == NULL
2206 || vers->vn_user[0] == '-'
2207 || RCS_isdead (vers->srcfile, vers->vn_user))
2214 /* If the user file has been marked for addition, or has been
2215 locally modified, then we have a conflict which we can not
2216 resolve. No_Difference will already have been called in
2217 this case, so comparing the timestamps is sufficient to
2218 determine whether the file is locally modified. */
2219 if (strcmp (vers->vn_user, "0") == 0
2220 || (vers->ts_user != NULL
2221 && strcmp (vers->ts_user, vers->ts_rcs) != 0))
2225 "file %s is locally modified, but has been removed in revision %s as of %s",
2226 finfo->fullname, jrev2, jdate2);
2229 "file %s is locally modified, but has been removed in revision %s",
2230 finfo->fullname, jrev2);
2232 /* FIXME: Should we arrange to return a non-zero exit
2241 /* If only one join tag was specified, and the user file has
2242 been changed since the greatest common ancestor (rev1),
2243 then there is a conflict we can not resolve. See above for
2245 if (join_rev2 == NULL
2246 && strcmp (rev1, vers->vn_user) != 0)
2250 "file %s has been modified, but has been removed in revision %s as of %s",
2251 finfo->fullname, jrev2, jdate2);
2254 "file %s has been modified, but has been removed in revision %s",
2255 finfo->fullname, jrev2);
2257 /* FIXME: Should we arrange to return a non-zero exit
2269 /* The user file exists and has not been modified. Mark it
2270 for removal. FIXME: If we are doing a checkout, this has
2271 the effect of first checking out the file, and then
2272 removing it. It would be better to just register the
2275 The same goes for a removal then an add. e.g.
2276 cvs up -rbr -jbr2 could remove and readd the same file
2278 /* save the rev since server_updated might invalidate it */
2279 mrev = xmalloc (strlen (vers->vn_user) + 2);
2280 sprintf (mrev, "-%s", vers->vn_user);
2281 #ifdef SERVER_SUPPORT
2284 server_scratch (finfo->file);
2285 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
2286 (unsigned char *) NULL, (struct buffer *) NULL);
2289 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
2290 vers->options, vers->tag, vers->date, vers->ts_conflict);
2292 /* We need to check existence_error here because if we are
2293 running as the server, and the file is up to date in the
2294 working directory, the client will not have sent us a copy. */
2295 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
2296 error (0, errno, "cannot remove file %s", finfo->fullname);
2297 #ifdef SERVER_SUPPORT
2299 server_checked_in (finfo->file, finfo->update_dir,
2303 error (0, 0, "scheduling `%s' for removal", finfo->fullname);
2308 /* If the two merge revisions are the same, then there is nothing
2309 * to do. This needs to be checked before the rev2 == up-to-date base
2310 * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
2311 * "already contains the changes between <rev1> and <rev1>" message.
2313 if (rev1 && strcmp (rev1, rev2) == 0)
2320 /* If we know that the user file is up-to-date, then it becomes an
2321 * optimization to skip the merge when rev2 is the same as the base
2322 * revision. i.e. we know that diff3(file2,file1,file2) will produce
2325 if (vers->vn_user != NULL && vers->ts_user != NULL
2326 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2327 && strcmp (rev2, vers->vn_user) == 0)
2331 cvs_output (finfo->fullname, 0);
2332 cvs_output (" already contains the differences between ", 0);
2333 cvs_output (rev1 ? rev1 : "creation", 0);
2334 cvs_output (" and ", 0);
2335 cvs_output (rev2, 0);
2336 cvs_output ("\n", 1);
2346 /* If rev1 is dead or does not exist, then the file was added
2347 between rev1 and rev2. */
2348 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2354 /* If the file does not exist in the working directory, then
2355 we can just check out the new revision and mark it for
2357 if (vers->vn_user == NULL)
2359 char *saved_options = options;
2362 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
2364 /* Reset any keyword expansion option. Otherwise, when a
2365 command like `cvs update -kk -jT1 -jT2' creates a new file
2366 (because a file had the T2 tag, but not T1), the subsequent
2367 commit of that just-added file effectively would set the
2368 admin `-kk' option for that file in the repository. */
2371 /* FIXME: If checkout_file fails, we should arrange to
2372 return a non-zero exit status. */
2373 status = checkout_file (finfo, xvers, 1, 0, 1);
2374 options = saved_options;
2376 freevers_ts (&xvers);
2381 /* The file currently exists in the working directory, so we
2382 have a conflict which we can not resolve. Note that this
2383 is true even if the file is marked for addition or removal. */
2387 "file %s exists, but has been added in revision %s as of %s",
2388 finfo->fullname, jrev2, jdate2);
2391 "file %s exists, but has been added in revision %s",
2392 finfo->fullname, jrev2);
2397 /* If there is no working file, then we can't do the merge. */
2398 if (vers->vn_user == NULL || vers->vn_user[0] == '-')
2405 "file %s does not exist, but is present in revision %s as of %s",
2406 finfo->fullname, jrev2, jdate2);
2409 "file %s does not exist, but is present in revision %s",
2410 finfo->fullname, jrev2);
2412 /* FIXME: Should we arrange to return a non-zero exit status? */
2417 #ifdef SERVER_SUPPORT
2418 if (server_active && !isreadable (finfo->file))
2421 /* The file is up to date. Need to check out the current contents. */
2422 /* FIXME - see the FIXME comment above the call to RCS_checkout in the
2423 * patch_file function.
2425 retcode = RCS_checkout (vers->srcfile, finfo->file,
2426 vers->vn_user, vers->tag,
2427 (char *) NULL, RUN_TTY,
2428 (RCSCHECKOUTPROC) NULL, (void *) NULL);
2431 "failed to check out %s file", finfo->fullname);
2436 * The users currently modified file is moved to a backup file name
2437 * ".#filename.version", so that it will stay around for a few days
2438 * before being automatically removed by some cron daemon. The "version"
2439 * is the version of the file that the user was most up-to-date with
2442 backup = xmalloc (strlen (finfo->file)
2443 + strlen (vers->vn_user)
2444 + sizeof (BAKPREFIX)
2446 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
2448 if (unlink_file (backup) < 0
2449 && !existence_error (errno))
2450 error (0, errno, "cannot remove %s", backup);
2451 copy_file (finfo->file, backup);
2452 xchmod (finfo->file, 1);
2454 t_options = vers->options;
2456 if (*t_options == '\0')
2457 t_options = "-kk"; /* to ignore keyword expansions */
2460 /* If the source of the merge is the same as the working file
2461 revision, then we can just RCS_checkout the target (no merging
2462 as such). In the text file case, this is probably quite
2463 similar to the RCS_merge, but in the binary file case,
2464 RCS_merge gives all kinds of trouble. */
2465 if (vers->vn_user != NULL
2466 && strcmp (rev1, vers->vn_user) == 0
2467 /* See comments above about how No_Difference has already been
2469 && vers->ts_user != NULL
2470 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2472 /* Avoid this in the text file case. See below for why.
2474 && (strcmp (t_options, "-kb") == 0
2475 || wrap_merge_is_copy (finfo->file)))
2477 /* FIXME: Verify my comment below:
2479 * RCS_merge does nothing with keywords. It merges the changes between
2480 * two revisions without expanding the keywords (it might expand in
2481 * -kk mode before computing the diff between rev1 and rev2 - I'm not
2482 * sure). In other words, the keyword lines in the current work file
2485 * Therfore, checking out the destination revision (rev2) is probably
2486 * incorrect in the text case since we should see the keywords that were
2487 * substituted into the original file at the time it was checked out
2488 * and not the keywords from rev2.
2490 * Also, it is safe to pass in NULL for nametag since we know no
2491 * substitution is happening during the binary mode checkout.
2493 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL, t_options,
2494 RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0 )
2499 /* OK, this is really stupid. RCS_checkout carefully removes
2500 write permissions, and we carefully put them back. But
2501 until someone gets around to fixing it, that seems like the
2502 easiest way to get what would seem to be the right mode.
2503 I don't check CVSWRITE or _watched; I haven't thought about
2504 that in great detail, but it seems like a watched file should
2505 be checked out (writable) after a merge. */
2506 xchmod (finfo->file, 1);
2508 /* Traditionally, the text file case prints a whole bunch of
2509 scary looking and verbose output which fails to tell the user
2510 what is really going on (it gives them rev1 and rev2 but doesn't
2511 indicate in any way that rev1 == vn_user). I think just a
2512 simple "U foo" is good here; it seems analogous to the case in
2513 which the file was added on the branch in terms of what to
2515 write_letter (finfo, 'U');
2517 else if (strcmp (t_options, "-kb") == 0
2518 || wrap_merge_is_copy (finfo->file)
2519 || special_file_mismatch (finfo, rev1, rev2))
2521 /* We are dealing with binary files, or files with a
2522 permission/linkage mismatch (this second case only occurs when
2523 PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
2524 need to take place. This is a conflict. We give the user
2525 the two files, and let them resolve it. It is possible
2526 that we should require a "touch foo" or similar step before
2527 we allow a checkin. */
2528 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL,
2529 t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
2534 /* OK, this is really stupid. RCS_checkout carefully removes
2535 write permissions, and we carefully put them back. But
2536 until someone gets around to fixing it, that seems like the
2537 easiest way to get what would seem to be the right mode.
2538 I don't check CVSWRITE or _watched; I haven't thought about
2539 that in great detail, but it seems like a watched file should
2540 be checked out (writable) after a merge. */
2541 xchmod (finfo->file, 1);
2543 /* Hmm. We don't give them REV1 anywhere. I guess most people
2544 probably don't have a 3-way merge tool for the file type in
2545 question, and might just get confused if we tried to either
2546 provide them with a copy of the file from REV1, or even just
2547 told them what REV1 is so they can get it themself, but it
2548 might be worth thinking about. */
2549 /* See comment in merge_file about the "nonmergeable file"
2551 error (0, 0, "nonmergeable file needs merge");
2552 error (0, 0, "revision %s from repository is now in %s",
2553 rev2, finfo->fullname);
2554 error (0, 0, "file from working directory is now in %s", backup);
2555 write_letter (finfo, 'C');
2558 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2559 t_options, rev1, rev2);
2565 error (0, status == -1 ? errno : 0,
2566 "could not merge revision %s of %s", rev2, finfo->fullname);
2567 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2568 finfo->fullname, backup);
2569 rename_file (backup, finfo->file);
2572 else /* status == 0 */
2574 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2575 xcmp on the temporary files without much hassle, I think. */
2576 if (!noexec && !xcmp (backup, finfo->file))
2580 cvs_output (finfo->fullname, 0);
2581 cvs_output (" already contains the differences between ", 0);
2582 cvs_output (rev1, 0);
2583 cvs_output (" and ", 0);
2584 cvs_output (rev2, 0);
2585 cvs_output ("\n", 1);
2588 /* and skip the registering and sending the new file since it
2589 * hasn't been updated.
2595 /* The file has changed, but if we just checked it out it may
2596 still have the same timestamp it did when it was first
2597 registered above in checkout_file. We register it again with a
2598 dummy timestamp to make sure that later runs of CVS will
2599 recognize that it has changed.
2601 We don't actually need to register again if we called
2602 RCS_checkout above, and we aren't running as the server.
2603 However, that is not the normal case, and calling Register
2604 again won't cost much in that case. */
2610 (void) time (&last_register_time);
2611 cp = time_stamp (finfo->file);
2613 Register (finfo->entries, finfo->file,
2614 vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge",
2615 vers->options, vers->tag, vers->date, cp);
2620 #ifdef SERVER_SUPPORT
2623 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
2625 server_updated (finfo, vers, SERVER_MERGED,
2626 (mode_t) -1, (unsigned char *) NULL,
2627 (struct buffer *) NULL);
2640 * Report whether revisions REV1 and REV2 of FINFO agree on:
2643 * . major and minor device numbers
2647 * If either REV1 or REV2 is NULL, the working copy is used instead.
2649 * Return 1 if the files differ on these data.
2653 special_file_mismatch (struct file_info *finfo, char *rev1, char *rev2)
2655 #ifdef PRESERVE_PERMISSIONS_SUPPORT
2659 uid_t rev1_uid, rev2_uid;
2660 gid_t rev1_gid, rev2_gid;
2661 mode_t rev1_mode, rev2_mode;
2662 unsigned long dev_long;
2663 dev_t rev1_dev, rev2_dev;
2664 char *rev1_symlink = NULL;
2665 char *rev2_symlink = NULL;
2666 List *rev1_hardlinks = NULL;
2667 List *rev2_hardlinks = NULL;
2668 int check_uids, check_gids, check_modes;
2671 /* If we don't care about special file info, then
2672 don't report a mismatch in any case. */
2673 if (!preserve_perms)
2676 /* When special_file_mismatch is called from No_Difference, the
2677 RCS file has been only partially parsed. We must read the
2678 delta tree in order to compare special file info recorded in
2679 the delta nodes. (I think this is safe. -twp) */
2680 if (finfo->rcs->flags & PARTIAL)
2681 RCS_reparsercsfile (finfo->rcs, NULL, NULL);
2683 check_uids = check_gids = check_modes = 1;
2685 /* Obtain file information for REV1. If this is null, then stat
2686 finfo->file and use that info. */
2687 /* If a revision does not know anything about its status,
2688 then presumably it doesn't matter, and indicates no conflict. */
2692 if (islink (finfo->file))
2693 rev1_symlink = xreadlink (finfo->file);
2696 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2697 if (CVS_LSTAT (finfo->file, &sb) < 0)
2698 error (1, errno, "could not get file information for %s",
2700 rev1_uid = sb.st_uid;
2701 rev1_gid = sb.st_gid;
2702 rev1_mode = sb.st_mode;
2703 if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
2704 rev1_dev = sb.st_rdev;
2706 error (1, 0, "cannot handle device files on this system (%s)",
2710 rev1_hardlinks = list_linked_files_on_disk (finfo->file);
2714 n = findnode (finfo->rcs->versions, rev1);
2717 n = findnode (vp->other_delta, "symlink");
2719 rev1_symlink = xstrdup (n->data);
2722 n = findnode (vp->other_delta, "owner");
2724 check_uids = 0; /* don't care */
2726 rev1_uid = strtoul (n->data, NULL, 10);
2728 n = findnode (vp->other_delta, "group");
2730 check_gids = 0; /* don't care */
2732 rev1_gid = strtoul (n->data, NULL, 10);
2734 n = findnode (vp->other_delta, "permissions");
2736 check_modes = 0; /* don't care */
2738 rev1_mode = strtoul (n->data, NULL, 8);
2740 n = findnode (vp->other_delta, "special");
2742 rev1_mode |= S_IFREG;
2745 /* If the size of `ftype' changes, fix the sscanf call also */
2747 if (sscanf (n->data, "%15s %lu", ftype,
2749 error (1, 0, "%s:%s has bad `special' newphrase %s",
2750 finfo->file, rev1, (char *)n->data);
2751 rev1_dev = dev_long;
2752 if (strcmp (ftype, "character") == 0)
2753 rev1_mode |= S_IFCHR;
2754 else if (strcmp (ftype, "block") == 0)
2755 rev1_mode |= S_IFBLK;
2757 error (0, 0, "%s:%s unknown file type `%s'",
2758 finfo->file, rev1, ftype);
2761 rev1_hardlinks = vp->hardlinks;
2762 if (rev1_hardlinks == NULL)
2763 rev1_hardlinks = getlist();
2767 /* Obtain file information for REV2. */
2770 if (islink (finfo->file))
2771 rev2_symlink = xreadlink (finfo->file);
2774 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2775 if (CVS_LSTAT (finfo->file, &sb) < 0)
2776 error (1, errno, "could not get file information for %s",
2778 rev2_uid = sb.st_uid;
2779 rev2_gid = sb.st_gid;
2780 rev2_mode = sb.st_mode;
2781 if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
2782 rev2_dev = sb.st_rdev;
2784 error (1, 0, "cannot handle device files on this system (%s)",
2788 rev2_hardlinks = list_linked_files_on_disk (finfo->file);
2792 n = findnode (finfo->rcs->versions, rev2);
2795 n = findnode (vp->other_delta, "symlink");
2797 rev2_symlink = xstrdup (n->data);
2800 n = findnode (vp->other_delta, "owner");
2802 check_uids = 0; /* don't care */
2804 rev2_uid = strtoul (n->data, NULL, 10);
2806 n = findnode (vp->other_delta, "group");
2808 check_gids = 0; /* don't care */
2810 rev2_gid = strtoul (n->data, NULL, 10);
2812 n = findnode (vp->other_delta, "permissions");
2814 check_modes = 0; /* don't care */
2816 rev2_mode = strtoul (n->data, NULL, 8);
2818 n = findnode (vp->other_delta, "special");
2820 rev2_mode |= S_IFREG;
2823 /* If the size of `ftype' changes, fix the sscanf call also */
2825 if (sscanf (n->data, "%15s %lu", ftype,
2827 error (1, 0, "%s:%s has bad `special' newphrase %s",
2828 finfo->file, rev2, (char *)n->data);
2829 rev2_dev = dev_long;
2830 if (strcmp (ftype, "character") == 0)
2831 rev2_mode |= S_IFCHR;
2832 else if (strcmp (ftype, "block") == 0)
2833 rev2_mode |= S_IFBLK;
2835 error (0, 0, "%s:%s unknown file type `%s'",
2836 finfo->file, rev2, ftype);
2839 rev2_hardlinks = vp->hardlinks;
2840 if (rev2_hardlinks == NULL)
2841 rev2_hardlinks = getlist();
2845 /* Check the user/group ownerships and file permissions, printing
2846 an error for each mismatch found. Return 0 if all characteristics
2847 matched, and 1 otherwise. */
2851 /* Compare symlinks first, since symlinks are simpler (don't have
2852 any other characteristics). */
2853 if (rev1_symlink != NULL && rev2_symlink == NULL)
2855 error (0, 0, "%s is a symbolic link",
2856 (rev1 == NULL ? "working file" : rev1));
2859 else if (rev1_symlink == NULL && rev2_symlink != NULL)
2861 error (0, 0, "%s is a symbolic link",
2862 (rev2 == NULL ? "working file" : rev2));
2865 else if (rev1_symlink != NULL)
2866 result = (strcmp (rev1_symlink, rev2_symlink) == 0);
2869 /* Compare user ownership. */
2870 if (check_uids && rev1_uid != rev2_uid)
2872 error (0, 0, "%s: owner mismatch between %s and %s",
2874 (rev1 == NULL ? "working file" : rev1),
2875 (rev2 == NULL ? "working file" : rev2));
2879 /* Compare group ownership. */
2880 if (check_gids && rev1_gid != rev2_gid)
2882 error (0, 0, "%s: group mismatch between %s and %s",
2884 (rev1 == NULL ? "working file" : rev1),
2885 (rev2 == NULL ? "working file" : rev2));
2889 /* Compare permissions. */
2891 (rev1_mode & 07777) != (rev2_mode & 07777))
2893 error (0, 0, "%s: permission mismatch between %s and %s",
2895 (rev1 == NULL ? "working file" : rev1),
2896 (rev2 == NULL ? "working file" : rev2));
2900 /* Compare device file characteristics. */
2901 if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
2903 error (0, 0, "%s: %s and %s are different file types",
2905 (rev1 == NULL ? "working file" : rev1),
2906 (rev2 == NULL ? "working file" : rev2));
2909 else if (S_ISBLK (rev1_mode))
2911 if (rev1_dev != rev2_dev)
2913 error (0, 0, "%s: device numbers of %s and %s do not match",
2915 (rev1 == NULL ? "working file" : rev1),
2916 (rev2 == NULL ? "working file" : rev2));
2921 /* Compare hard links. */
2922 if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
2924 error (0, 0, "%s: hard linkage of %s and %s do not match",
2926 (rev1 == NULL ? "working file" : rev1),
2927 (rev2 == NULL ? "working file" : rev2));
2932 if (rev1_symlink != NULL)
2933 free (rev1_symlink);
2934 if (rev2_symlink != NULL)
2935 free (rev2_symlink);
2936 if (rev1_hardlinks != NULL)
2937 dellist (&rev1_hardlinks);
2938 if (rev2_hardlinks != NULL)
2939 dellist (&rev2_hardlinks);
2952 return join_rev1 != NULL;