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
50 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
51 int adding, int merging, int update_server));
53 static void checkout_to_buffer PROTO ((void *, const char *, size_t));
54 static int patch_file PROTO ((struct file_info *finfo,
56 int *docheckout, struct stat *file_info,
57 unsigned char *checksum));
58 static void patch_file_write PROTO ((void *, const char *, size_t));
59 #endif /* SERVER_SUPPORT */
60 static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
61 static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers));
62 static Dtype update_dirent_proc PROTO ((void *callerdat, const char *dir,
63 const char *repository,
64 const char *update_dir,
66 static int update_dirleave_proc PROTO ((void *callerdat, const char *dir,
67 int err, const char *update_dir,
69 static int update_fileproc PROTO ((void *callerdat, struct file_info *));
70 static int update_filesdone_proc PROTO ((void *callerdat, int err,
71 const char *repository,
72 const char *update_dir,
74 #ifdef PRESERVE_PERMISSIONS_SUPPORT
75 static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *));
77 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
79 static char *options = NULL;
80 static char *tag = NULL;
81 static char *date = NULL;
82 /* This is a bit of a kludge. We call WriteTag at the beginning
83 before we know whether nonbranch is set or not. And then at the
84 end, once we have the right value for nonbranch, we call WriteTag
85 again. I don't know whether the first call is necessary or not.
86 rewrite_tag is nonzero if we are going to have to make that second
88 static int rewrite_tag;
91 /* If we set the tag or date for a subdirectory, we use this to undo
92 the setting. See update_dirent_proc. */
93 static char *tag_update_dir;
95 static char *join_rev1, *date_rev1;
96 static char *join_rev2, *date_rev2;
98 static int toss_local_changes = 0;
99 static int force_tag_match = 1;
100 static int pull_template = 0;
101 static int update_build_dirs = 0;
102 static int update_prune_dirs = 0;
103 static int pipeout = 0;
104 #ifdef SERVER_SUPPORT
105 static int patches = 0;
106 static int rcs_diff_patches = 0;
108 static List *ignlist = (List *) NULL;
109 static time_t last_register_time;
110 static const char *const update_usage[] =
112 "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n",
113 " [-I ign] [-W spec] [files...]\n",
114 "\t-A\tReset any sticky tags/date/kopts.\n",
115 "\t-P\tPrune empty directories.\n",
116 "\t-C\tOverwrite locally modified files with clean repository copies.\n",
117 "\t-d\tBuild directories, like checkout does.\n",
118 "\t-f\tForce a head revision match if tag/date not found.\n",
119 "\t-l\tLocal directory only, no recursion.\n",
120 "\t-R\tProcess directories recursively.\n",
121 "\t-p\tSend updates to standard output (avoids stickiness).\n",
122 "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
123 "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
124 "\t-D date\tSet date to update from (is sticky).\n",
125 "\t-j rev\tMerge in changes made between current revision and rev.\n",
126 "\t-I ign\tMore files to ignore (! to reset).\n",
127 "\t-W spec\tWrappers specification line.\n",
128 "\t-T\tCreate CVS/Template.\n",
129 "(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
142 int local = 0; /* recursive by default */
143 int which; /* where to look for files and dirs */
144 int xpull_template = 0;
147 usage (update_usage);
154 while ((c = getopt (argc, argv, "+ApCPflRQTqduk:r:D:j:I:W:")) != -1)
162 toss_local_changes = 1;
168 wrap_add (optarg, 0);
173 options = RCS_check_kflag (optarg);
183 #ifdef SERVER_SUPPORT
184 /* The CVS 1.5 client sends these options (in addition to
185 Global_option requests), so we must ignore them. */
189 "-q or -Q must be specified before \"%s\"",
196 update_build_dirs = 1;
205 date = Make_Date (optarg);
208 update_prune_dirs = 1;
212 noexec = 1; /* so no locks will be created */
216 error (1, 0, "only two -j options can be specified");
223 #ifdef SERVER_SUPPORT
227 rcs_diff_patches = server_use_rcs_diff ();
231 usage (update_usage);
235 usage (update_usage);
242 #ifdef CLIENT_SUPPORT
243 if (current_parsed_root->isremote)
247 /* The first pass does the regular update. If we receive at least
248 one patch which failed, we do a second pass and just fetch
249 those files whose patches failed. */
259 if (update_build_dirs)
263 if (!force_tag_match)
267 if (toss_local_changes)
269 if (update_prune_dirs)
271 client_prune_dirs = update_prune_dirs;
272 option_with_arg ("-r", tag);
273 if (options && options[0] != '\0')
276 client_senddate (date);
278 option_with_arg ("-j", join_rev1);
280 option_with_arg ("-j", join_rev2);
283 if (failed_patches_count == 0)
285 unsigned int flags = 0;
287 /* If the server supports the command "update-patches", that
288 means that it knows how to handle the -u argument to update,
289 which means to send patches instead of complete files.
291 We don't send -u if failed_patches != NULL, so that the
292 server doesn't try to send patches which will just fail
293 again. At least currently, the client also clobbers the
294 file and tells the server it is lost, which also will get
295 a full file instead of a patch, but it seems clean to omit
297 if (supported_request ("update-patches"))
302 if (update_build_dirs)
303 flags |= SEND_BUILD_DIRS;
305 if (toss_local_changes) {
306 flags |= SEND_NO_CONTENTS;
307 flags |= BACKUP_MODIFIED_FILES;
310 /* If noexec, probably could be setting SEND_NO_CONTENTS.
311 Same caveats as for "cvs status" apply. */
313 send_files (argc, argv, local, aflag, flags);
314 send_file_names (argc, argv, SEND_EXPAND_WILD);
320 (void) printf ("%s client: refetching unpatchable files\n",
323 if (toplevel_wd != NULL
324 && CVS_CHDIR (toplevel_wd) < 0)
326 error (1, errno, "could not chdir to %s", toplevel_wd);
331 for (i = 0; i < failed_patches_count; i++)
332 if (unlink_file (failed_patches[i]) < 0
333 && !existence_error (errno))
334 error (0, errno, "cannot remove %s",
336 send_files (failed_patches_count, failed_patches, local,
337 aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
338 send_file_names (failed_patches_count, failed_patches, 0);
339 free_names (&failed_patches_count, failed_patches);
342 send_to_server ("update\012", 0);
344 status = get_responses_and_close ();
346 /* If there are any conflicts, the server will return a
347 non-zero exit status. If any patches failed, we still
348 want to run the update again. We use a pass count to
349 avoid an endless loop. */
351 /* Notes: (1) assuming that status != 0 implies a
352 potential conflict is the best we can cleanly do given
353 the current protocol. I suppose that trying to
354 re-fetch in cases where there was a more serious error
355 is probably more or less harmless, but it isn't really
356 ideal. (2) it would be nice to have a testsuite case for the
357 conflict-and-patch-failed case. */
360 && (failed_patches_count == 0 || pass > 1))
362 if (failed_patches_count > 0)
363 free_names (&failed_patches_count, failed_patches);
368 } while (failed_patches_count > 0);
375 tag_check_valid (tag, argc, argv, local, aflag, "");
376 if (join_rev1 != NULL)
377 tag_check_valid_join (join_rev1, argc, argv, local, aflag, "");
378 if (join_rev2 != NULL)
379 tag_check_valid_join (join_rev2, argc, argv, local, aflag, "");
382 * If we are updating the entire directory (for real) and building dirs
383 * as we go, we make sure there is no static entries file and write the
384 * tag file as appropriate
386 if (argc <= 0 && !pipeout)
388 if (update_build_dirs)
390 if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
391 error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
392 #ifdef SERVER_SUPPORT
395 char *repos = Name_Repository (NULL, NULL);
396 server_clear_entstat (".", repos);
402 /* keep the CVS/Tag file current with the specified arguments */
403 if (aflag || tag || date)
405 char *repos = Name_Repository (NULL, NULL);
406 WriteTag ((char *) NULL, tag, date, 0, ".", repos);
413 /* look for files/dirs locally and in the repository */
414 which = W_LOCAL | W_REPOS;
416 /* look in the attic too if a tag or date is specified */
417 if (tag != NULL || date != NULL || joining())
420 /* call the command line interface */
421 err = do_update (argc, argv, options, tag, date, force_tag_match,
422 local, update_build_dirs, aflag, update_prune_dirs,
423 pipeout, which, join_rev1, join_rev2, (char *) NULL,
424 xpull_template, (char *) NULL);
426 /* free the space Make_Date allocated if necessary */
436 * Command line interface to update (used by checkout)
439 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
440 xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir,
441 xpull_template, repository)
456 char *preload_update_dir;
463 /* fill in the statics */
467 force_tag_match = xforce;
468 update_build_dirs = xbuild;
470 update_prune_dirs = xprune;
472 pull_template = xpull_template;
474 /* setup the join support */
475 join_rev1 = xjoin_rev1;
476 join_rev2 = xjoin_rev2;
477 if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
480 date_rev1 = Make_Date (cp);
483 date_rev1 = (char *) NULL;
484 if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
487 date_rev2 = Make_Date (cp);
490 date_rev2 = (char *) NULL;
492 #ifdef PRESERVE_PERMISSIONS_SUPPORT
495 /* We need to do an extra recursion, bleah. It's to make sure
496 that we know as much as possible about file linkage. */
497 hardlist = getlist();
498 working_dir = xgetwd(); /* save top-level working dir */
500 /* FIXME-twp: the arguments to start_recursion make me dizzy. This
501 function call was copied from the update_fileproc call that
502 follows it; someone should make sure that I did it right. */
503 err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL,
504 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
505 argc, argv, local, which, aflag, CVS_LOCK_READ,
506 preload_update_dir, 1, (char *) NULL);
510 /* FIXME-twp: at this point we should walk the hardlist
511 and update the `links' field of each hardlink_info struct
512 to list the files that are linked on dist. That would make
513 it easier & more efficient to compare the disk linkage with
514 the repository linkage (a simple strcmp). */
518 /* call the recursion processor */
519 err = start_recursion (update_fileproc, update_filesdone_proc,
520 update_dirent_proc, update_dirleave_proc, NULL,
521 argc, argv, local, which, aflag, CVS_LOCK_READ,
522 preload_update_dir, 1, repository);
524 #ifdef SERVER_SUPPORT
529 /* see if we need to sleep before returning to avoid time-stamp races */
530 if (last_register_time)
532 sleep_past (last_register_time);
538 #ifdef PRESERVE_PERMISSIONS_SUPPORT
540 * The get_linkinfo_proc callback adds each file to the hardlist
545 get_linkinfo_proc (callerdat, finfo)
547 struct file_info *finfo;
551 struct hardlink_info *hlinfo;
553 /* Get the full pathname of the current file. */
554 fullpath = xmalloc (strlen(working_dir) +
555 strlen(finfo->fullname) + 2);
556 sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
558 /* To permit recursing into subdirectories, files
559 are keyed on the full pathname and not on the basename. */
560 linkp = lookup_file_by_inode (fullpath);
563 /* The file isn't on disk; we are probably restoring
564 a file that was removed. */
568 /* Create a new, empty hardlink_info node. */
569 hlinfo = (struct hardlink_info *)
570 xmalloc (sizeof (struct hardlink_info));
572 hlinfo->status = (Ctype) 0; /* is this dumb? */
573 hlinfo->checked_out = 0;
575 linkp->data = hlinfo;
584 * This is the callback proc for update. It is called for each file in each
585 * directory by the recursion code. The current directory is the local
586 * instantiation. file is the file name we are to operate on. update_dir is
587 * set to the path relative to where we started (for pretty printing).
588 * repository is the repository. entries and srcfiles are the pre-parsed
589 * entries and source control files.
591 * This routine decides what needs to be done for each file and does the
592 * appropriate magic for checkout
595 update_fileproc (callerdat, finfo)
597 struct file_info *finfo;
603 status = Classify_File (finfo, tag, date, options, force_tag_match,
604 aflag, &vers, pipeout);
606 /* Keep track of whether TAG is a branch tag.
607 Note that if it is a branch tag in some files and a nonbranch tag
608 in others, treat it as a nonbranch tag. It is possible that case
609 should elicit a warning or an error. */
612 && finfo->rcs != NULL)
614 char *rev = RCS_getversion (finfo->rcs, tag, date, 1, NULL);
616 && !RCS_nodeisbranch (finfo->rcs, tag))
625 * We just return success without doing anything if any of the really
628 * If there is still a valid RCS file, do a regular checkout type
633 case T_UNKNOWN: /* unknown file was explicitly asked
635 case T_REMOVE_ENTRY: /* needs to be un-registered */
636 case T_ADDED: /* added but not committed */
639 case T_CONFLICT: /* old punt-type errors */
642 case T_UPTODATE: /* file was already up-to-date */
643 case T_NEEDS_MERGE: /* needs merging */
644 case T_MODIFIED: /* locally modified */
645 case T_REMOVED: /* removed but not committed */
646 case T_CHECKOUT: /* needs checkout */
647 case T_PATCH: /* needs patch */
648 retval = checkout_file (finfo, vers, 0, 0, 0);
651 default: /* can't ever happen :-) */
653 "unknown file status %d for file %s", status, finfo->file);
662 case T_UNKNOWN: /* unknown file was explicitly asked
664 case T_UPTODATE: /* file was already up-to-date */
667 case T_CONFLICT: /* old punt-type errors */
669 write_letter (finfo, 'C');
671 case T_NEEDS_MERGE: /* needs merging */
672 if (! toss_local_changes)
674 retval = merge_file (finfo, vers);
677 /* else FALL THROUGH */
678 case T_MODIFIED: /* locally modified */
680 if (toss_local_changes)
683 bakname = backup_file (finfo->file, vers->vn_user);
684 /* This behavior is sufficiently unexpected to
685 justify overinformativeness, I think. */
686 #ifdef SERVER_SUPPORT
687 if ((! really_quiet) && (! server_active))
688 #else /* ! SERVER_SUPPORT */
690 #endif /* SERVER_SUPPORT */
691 (void) printf ("(Locally modified %s moved to %s)\n",
692 finfo->file, bakname);
695 /* The locally modified file is still present, but
696 it will be overwritten by the repository copy
699 retval = checkout_file (finfo, vers, 0, 0, 1);
703 if (vers->ts_conflict)
705 if (file_has_conflict (finfo, vers->ts_conflict)
706 || file_has_markers (finfo))
708 write_letter (finfo, 'C');
713 /* Reregister to clear conflict flag. */
714 Register (finfo->entries, finfo->file,
715 vers->vn_rcs, vers->ts_rcs,
716 vers->options, vers->tag,
717 vers->date, (char *)0);
721 write_letter (finfo, 'M');
724 case T_PATCH: /* needs patch */
725 #ifdef SERVER_SUPPORT
729 struct stat file_info;
730 unsigned char checksum[16];
732 retval = patch_file (finfo,
734 &file_info, checksum);
737 if (server_active && retval == 0)
738 server_updated (finfo, vers,
742 file_info.st_mode, checksum,
743 (struct buffer *) NULL);
748 /* If we're not running as a server, just check the
749 file out. It's simpler and faster than producing
750 and applying patches. */
752 case T_CHECKOUT: /* needs checkout */
753 retval = checkout_file (finfo, vers, 0, 0, 1);
755 case T_ADDED: /* added but not committed */
756 write_letter (finfo, 'A');
759 case T_REMOVED: /* removed but not committed */
760 write_letter (finfo, 'R');
763 case T_REMOVE_ENTRY: /* needs to be un-registered */
764 retval = scratch_file (finfo, vers);
766 default: /* can't ever happen :-) */
768 "unknown file status %d for file %s", status, finfo->file);
774 /* only try to join if things have gone well thus far */
775 if (retval == 0 && join_rev1)
776 join_file (finfo, vers);
778 /* if this directory has an ignore list, add this file to it */
779 if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
785 p->key = xstrdup (finfo->file);
786 if (addnode (ignlist, p) != 0)
796 static void update_ignproc PROTO ((const char *, const char *));
799 update_ignproc (file, dir)
803 struct file_info finfo;
806 memset (&finfo, 0, sizeof (finfo));
808 finfo.update_dir = dir;
810 tmp = xstrdup (file);
813 tmp = xmalloc (strlen (file) + strlen (dir) + 10);
819 finfo.fullname = tmp;
820 write_letter (&finfo, '?');
828 update_filesdone_proc (callerdat, err, repository, update_dir, entries)
831 const char *repository;
832 const char *update_dir;
837 WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
841 /* if this directory has an ignore list, process it then free it */
844 ignore_files (ignlist, entries, update_dir, update_ignproc);
848 /* Clean up CVS admin dirs if we are export */
849 if (strcmp (cvs_cmd_name, "export") == 0)
851 /* I'm not sure the existence_error is actually possible (except
852 in cases where we really should print a message), but since
853 this code used to ignore all errors, I'll play it safe. */
854 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
855 error (0, errno, "cannot remove %s directory", CVSADM);
857 #ifdef SERVER_SUPPORT
858 else if (!server_active && !pipeout)
861 #endif /* SERVER_SUPPORT */
863 /* If there is no CVS/Root file, add one */
864 if (!isfile (CVSADM_ROOT))
865 Create_Root ((char *) NULL, current_parsed_root->original);
874 * update_dirent_proc () is called back by the recursion processor before a
875 * sub-directory is processed for update. In this case, update_dirent proc
876 * will probably create the directory unless -d isn't specified and this is a
877 * new directory. A return code of 0 indicates the directory should be
878 * processed by the recursion code. A return of non-zero indicates the
879 * recursion code should skip this directory.
882 update_dirent_proc (callerdat, dir, repository, update_dir, entries)
885 const char *repository;
886 const char *update_dir;
889 if (ignore_directory (update_dir))
891 /* print the warm fuzzy message */
893 error (0, 0, "Ignoring %s", update_dir);
899 /* if we aren't building dirs, blow it off */
900 if (!update_build_dirs)
903 /* Various CVS administrators are in the habit of removing
904 the repository directory for things they don't want any
905 more. I've even been known to do it myself (on rare
906 occasions). Not the usual recommended practice, but we
907 want to try to come up with some kind of
908 reasonable/documented/sensible behavior. Generally
909 the behavior is to just skip over that directory (see
910 dirs test in sanity.sh; the case which reaches here
911 is when update -d is specified, and the working directory
912 is gone but the subdirectory is still mentioned in
915 #ifdef SERVER_SUPPORT
916 /* In the remote case, the client should refrain from
917 sending us the directory in the first place. So we
918 want to continue to give an error, so clients make
922 && !isdir (repository))
927 /* ignore the missing dir if -n is specified */
928 error (0, 0, "New directory `%s' -- ignored", update_dir);
933 /* otherwise, create the dir and appropriate adm files */
935 /* If no tag or date were specified on the command line,
936 and we're not using -A, we want the subdirectory to use
937 the tag and date, if any, of the current directory.
938 That way, update -d will work correctly when working on
941 We use TAG_UPDATE_DIR to undo the tag setting in
942 update_dirleave_proc. If we did not do this, we would
943 not correctly handle a working directory with multiple
944 tags (and maybe we should prohibit such working
945 directories, but they work now and we shouldn't make
946 them stop working without more thought). */
947 if ((tag == NULL && date == NULL) && ! aflag)
949 ParseTag (&tag, &date, &nonbranch);
950 if (tag != NULL || date != NULL)
951 tag_update_dir = xstrdup (update_dir);
954 make_directory (dir);
955 Create_Admin (dir, update_dir, repository, tag, date,
956 /* This is a guess. We will rewrite it later
963 Subdir_Register (entries, (char *) NULL, dir);
966 /* Do we need to check noexec here? */
971 /* The directory exists. Check to see if it has a CVS
974 cvsadmdir = xmalloc (strlen (dir) + 80);
975 strcpy (cvsadmdir, dir);
976 strcat (cvsadmdir, "/");
977 strcat (cvsadmdir, CVSADM);
979 if (!isdir (cvsadmdir))
981 /* We cannot successfully recurse into a directory without a CVS
982 subdirectory. Generally we will have already printed
991 * If we are building dirs and not going to stdout, we make sure there is
992 * no static entries file and write the tag file as appropriate
996 if (update_build_dirs)
1000 tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10);
1001 (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
1002 if (unlink_file (tmp) < 0 && ! existence_error (errno))
1003 error (1, errno, "cannot remove file %s", tmp);
1004 #ifdef SERVER_SUPPORT
1006 server_clear_entstat (update_dir, repository);
1011 /* keep the CVS/Tag file current with the specified arguments */
1012 if (aflag || tag || date)
1014 WriteTag (dir, tag, date, 0, update_dir, repository);
1019 /* keep the CVS/Template file current */
1022 WriteTemplate (dir, update_dir);
1025 /* initialize the ignore list for this directory */
1026 ignlist = getlist ();
1029 /* print the warm fuzzy message */
1031 error (0, 0, "Updating %s", update_dir);
1039 * update_dirleave_proc () is called back by the recursion code upon leaving
1040 * a directory. It will prune empty directories if needed and will execute
1041 * any appropriate update programs.
1045 update_dirleave_proc (callerdat, dir, err, update_dir, entries)
1049 const char *update_dir;
1052 /* Delete the ignore list if it hasn't already been done. */
1056 /* If we set the tag or date for a new subdirectory in
1057 update_dirent_proc, and we're now done with that subdirectory,
1058 undo the tag/date setting. Note that we know that the tag and
1059 date were both originally NULL in this case. */
1060 if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
1073 free (tag_update_dir);
1074 tag_update_dir = NULL;
1077 if (strchr (dir, '/') == NULL)
1079 /* FIXME: chdir ("..") loses with symlinks. */
1080 /* Prune empty dirs on the way out - if necessary */
1081 (void) CVS_CHDIR ("..");
1082 if (update_prune_dirs && isemptydir (dir, 0))
1084 /* I'm not sure the existence_error is actually possible (except
1085 in cases where we really should print a message), but since
1086 this code used to ignore all errors, I'll play it safe. */
1087 if (unlink_file_dir (dir) < 0 && !existence_error (errno))
1088 error (0, errno, "cannot remove %s directory", dir);
1089 Subdir_Deregister (entries, (char *) NULL, dir);
1098 static int isremoved PROTO ((Node *, void *));
1100 /* Returns 1 if the file indicated by node has been removed. */
1102 isremoved (node, closure)
1106 Entnode *entdata = node->data;
1108 /* If the first character of the version is a '-', the file has been
1110 return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
1115 /* Returns 1 if the argument directory is completely empty, other than the
1116 existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
1117 and the directory doesn't exist, then just return 0. */
1119 isemptydir (dir, might_not_exist)
1121 int might_not_exist;
1126 if ((dirp = CVS_OPENDIR (dir)) == NULL)
1128 if (might_not_exist && existence_error (errno))
1130 error (0, errno, "cannot open directory %s for empty check", dir);
1134 while ((dp = CVS_READDIR (dirp)) != NULL)
1136 if (strcmp (dp->d_name, ".") != 0
1137 && strcmp (dp->d_name, "..") != 0)
1139 if (strcmp (dp->d_name, CVSADM) != 0)
1141 /* An entry other than the CVS directory. The directory
1142 is certainly not empty. */
1143 (void) CVS_CLOSEDIR (dirp);
1148 /* The CVS directory entry. We don't have to worry about
1149 this unless the Entries file indicates that files have
1150 been removed, but not committed, in this directory.
1151 (Removing the directory would prevent people from
1152 comitting the fact that they removed the files!) */
1155 struct saved_cwd cwd;
1157 if (save_cwd (&cwd))
1160 if (CVS_CHDIR (dir) < 0)
1161 error (1, errno, "cannot change directory to %s", dir);
1162 l = Entries_Open (0, NULL);
1163 files_removed = walklist (l, isremoved, 0);
1166 if (restore_cwd (&cwd, NULL))
1170 if (files_removed != 0)
1172 /* There are files that have been removed, but not
1173 committed! Do not consider the directory empty. */
1174 (void) CVS_CLOSEDIR (dirp);
1183 error (0, errno, "cannot read directory %s", dir);
1184 (void) CVS_CLOSEDIR (dirp);
1187 (void) CVS_CLOSEDIR (dirp);
1194 * scratch the Entries file entry associated with a file
1197 scratch_file (finfo, vers)
1198 struct file_info *finfo;
1201 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
1202 Scratch_Entry (finfo->entries, finfo->file);
1203 #ifdef SERVER_SUPPORT
1206 if (vers->ts_user == NULL)
1207 server_scratch_entry_only ();
1208 server_updated (finfo, vers,
1209 SERVER_UPDATED, (mode_t) -1,
1210 (unsigned char *) NULL,
1211 (struct buffer *) NULL);
1214 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1215 error (0, errno, "unable to remove %s", finfo->fullname);
1217 #ifdef SERVER_SUPPORT
1218 /* skip this step when the server is running since
1219 * server_updated should have handled it */
1223 /* keep the vers structure up to date in case we do a join
1224 * - if there isn't a file, it can't very well have a version number, can it?
1226 if (vers->vn_user != NULL)
1228 free (vers->vn_user);
1229 vers->vn_user = NULL;
1231 if (vers->ts_user != NULL)
1233 free (vers->ts_user);
1234 vers->ts_user = NULL;
1246 checkout_file (finfo, vers_ts, adding, merging, update_server)
1247 struct file_info *finfo;
1254 int set_time, retval = 0;
1257 struct buffer *revbuf;
1262 /* Don't screw with backup files if we're going to stdout, or if
1263 we are the server. */
1265 #ifdef SERVER_SUPPORT
1270 backup = xmalloc (strlen (finfo->file)
1272 + sizeof (CVSPREFIX)
1274 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1275 if (isfile (finfo->file))
1276 rename_file (finfo->file, backup);
1279 /* If -f/-t wrappers are being used to wrap up a directory,
1280 then backup might be a directory instead of just a file. */
1281 if (unlink_file_dir (backup) < 0)
1283 /* Not sure if the existence_error check is needed here. */
1284 if (!existence_error (errno))
1285 /* FIXME: should include update_dir in message. */
1286 error (0, errno, "error removing %s", backup);
1293 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
1298 * if we are checking out to stdout, print a nice message to
1299 * stderr, and add the -p flag to the command */
1305 ===================================================================\n\
1307 cvs_outerr (finfo->fullname, 0);
1310 cvs_outerr (vers_ts->srcfile->path, 0);
1313 cvs_outerr (vers_ts->vn_rcs, 0);
1314 cvs_outerr ("\n***************\n", 0);
1318 #ifdef SERVER_SUPPORT
1322 && ! file_gzip_level
1324 && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
1326 revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL);
1327 status = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1328 vers_ts->vn_rcs, vers_ts->tag,
1329 vers_ts->options, RUN_TTY,
1330 checkout_to_buffer, revbuf);
1334 status = RCS_checkout (vers_ts->srcfile,
1335 pipeout ? NULL : finfo->file,
1336 vers_ts->vn_rcs, vers_ts->tag,
1337 vers_ts->options, RUN_TTY,
1338 (RCSCHECKOUTPROC) NULL, (void *) NULL);
1340 if (file_is_dead || status == 0)
1350 if (revbuf != NULL && !noexec)
1354 /* FIXME: We should have RCS_checkout return the mode.
1355 That would also fix the kludge with noexec, above, which
1356 is here only because noexec doesn't write srcfile->path
1358 if (stat (vers_ts->srcfile->path, &sb) < 0)
1361 error (1, errno, "cannot stat %s",
1362 vers_ts->srcfile->path);
1364 mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
1369 && !fileattr_get (finfo->file, "_watched"))
1372 xchmod (finfo->file, 1);
1375 /* We know that we are the server here, so
1376 although xchmod checks umask, we don't bother. */
1377 mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
1378 | ((mode & S_IRGRP) ? S_IWGRP : 0)
1379 | ((mode & S_IROTH) ? S_IWOTH : 0));
1384 /* A newly checked out file is never under the spell
1385 of "cvs edit". If we think we were editing it
1386 from a previous life, clean up. Would be better to
1387 check for same the working directory instead of
1388 same user, but that is hairy. */
1390 struct addremove_args args;
1392 editor_set (finfo->file, getcaller (), NULL);
1394 memset (&args, 0, sizeof args);
1395 args.remove_temp = 1;
1396 watch_modify_watchers (finfo->file, &args);
1399 /* set the time from the RCS file iff it was unknown before */
1402 && (vers_ts->vn_user == NULL ||
1403 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
1406 wrap_fromcvs_process_file (finfo->file);
1408 xvers_ts = Version_TS (finfo, options, tag, date,
1409 force_tag_match, set_time);
1410 if (strcmp (xvers_ts->options, "-V4") == 0)
1411 xvers_ts->options[0] = '\0';
1415 /* If we stored the file data into a buffer, then we
1416 didn't create a file at all, so xvers_ts->ts_user
1417 is wrong. The correct value is to have it be the
1418 same as xvers_ts->ts_rcs, meaning that the working
1419 file is unchanged from the RCS file.
1421 FIXME: We should tell Version_TS not to waste time
1422 statting the nonexistent file.
1424 FIXME: Actually, I don't think the ts_user value
1425 matters at all here. The only use I know of is
1426 that it is printed in a trace message by
1429 if (xvers_ts->ts_user != NULL)
1430 free (xvers_ts->ts_user);
1431 xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
1434 (void) time (&last_register_time);
1438 if (xvers_ts->vn_user != NULL)
1441 "warning: %s is not (any longer) pertinent",
1444 Scratch_Entry (finfo->entries, finfo->file);
1445 #ifdef SERVER_SUPPORT
1446 if (server_active && xvers_ts->ts_user == NULL)
1447 server_scratch_entry_only ();
1449 /* FIXME: Rather than always unlink'ing, and ignoring the
1450 existence_error, we should do the unlink only if
1451 vers_ts->ts_user is non-NULL. Then there would be no
1452 need to ignore an existence_error (for example, if the
1453 user removes the file while we are running). */
1454 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1456 error (0, errno, "cannot remove %s", finfo->fullname);
1460 Register (finfo->entries, finfo->file,
1461 adding ? "0" : xvers_ts->vn_rcs,
1462 xvers_ts->ts_user, xvers_ts->options,
1463 xvers_ts->tag, xvers_ts->date,
1464 (char *)0); /* Clear conflict flag on fresh checkout */
1466 /* fix up the vers structure, in case it is used by join */
1469 /* FIXME: Throwing away the original revision info is almost
1470 certainly wrong -- what if join_rev1 is "BASE"? */
1471 if (vers_ts->vn_user != NULL)
1472 free (vers_ts->vn_user);
1473 if (vers_ts->vn_rcs != NULL)
1474 free (vers_ts->vn_rcs);
1475 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1476 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1479 /* If this is really Update and not Checkout, recode history */
1480 if (strcmp (cvs_cmd_name, "update") == 0)
1481 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1484 freevers_ts (&xvers_ts);
1486 if (!really_quiet && !file_is_dead)
1488 write_letter (finfo, 'U');
1492 #ifdef SERVER_SUPPORT
1493 if (update_server && server_active)
1494 server_updated (finfo, vers_ts,
1495 merging ? SERVER_MERGED : SERVER_UPDATED,
1496 mode, (unsigned char *) NULL, revbuf);
1503 rename_file (backup, finfo->file);
1508 error (0, 0, "could not check out %s", finfo->fullname);
1515 /* If -f/-t wrappers are being used to wrap up a directory,
1516 then backup might be a directory instead of just a file. */
1517 if (unlink_file_dir (backup) < 0)
1519 /* Not sure if the existence_error check is needed here. */
1520 if (!existence_error (errno))
1521 /* FIXME: should include update_dir in message. */
1522 error (0, errno, "error removing %s", backup);
1534 #ifdef SERVER_SUPPORT
1536 /* This function is used to write data from a file being checked out
1540 checkout_to_buffer (callerdat, data, len)
1545 struct buffer *buf = (struct buffer *) callerdat;
1547 buf_output (buf, data, len);
1550 #endif /* SERVER_SUPPORT */
1552 #ifdef SERVER_SUPPORT
1554 /* This structure is used to pass information between patch_file and
1555 patch_file_write. */
1557 struct patch_file_data
1559 /* File name, for error messages. */
1560 const char *filename;
1561 /* File to which to write. */
1563 /* Whether to compute the MD5 checksum. */
1564 int compute_checksum;
1565 /* Data structure for computing the MD5 checksum. */
1566 struct cvs_MD5Context context;
1567 /* Set if the file has a final newline. */
1571 /* Patch a file. Runs diff. This is only done when running as the
1572 * server. The hope is that the diff will be smaller than the file
1576 patch_file (finfo, vers_ts, docheckout, file_info, checksum)
1577 struct file_info *finfo;
1580 struct stat *file_info;
1581 unsigned char *checksum;
1590 struct patch_file_data data;
1594 if (noexec || pipeout || joining ())
1600 /* If this file has been marked as being binary, then never send a
1602 if (strcmp (vers_ts->options, "-kb") == 0)
1608 /* First check that the first revision exists. If it has been nuked
1609 by cvs admin -o, then just fall back to checking out entire
1610 revisions. In some sense maybe we don't have to do this; after
1611 all cvs.texinfo says "Make sure that no-one has checked out a
1612 copy of the revision you outdate" but then again, that advice
1613 doesn't really make complete sense, because "cvs admin" operates
1614 on a working directory and so _someone_ will almost always have
1615 _some_ revision checked out. */
1619 rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
1629 /* If the revision is dead, let checkout_file handle it rather
1630 than duplicating the processing here. */
1631 if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
1637 backup = xmalloc (strlen (finfo->file)
1639 + sizeof (CVSPREFIX)
1641 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1642 if (isfile (finfo->file))
1643 rename_file (finfo->file, backup);
1646 if (unlink_file (backup) < 0
1647 && !existence_error (errno))
1648 error (0, errno, "cannot remove %s", backup);
1651 file1 = xmalloc (strlen (finfo->file)
1653 + sizeof (CVSPREFIX)
1655 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1656 file2 = xmalloc (strlen (finfo->file)
1658 + sizeof (CVSPREFIX)
1660 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1664 /* We need to check out both revisions first, to see if either one
1665 has a trailing newline. Because of this, we don't use rcsdiff,
1666 but just use diff. */
1668 e = CVS_FOPEN (file1, "w");
1670 error (1, errno, "cannot open %s", file1);
1672 data.filename = file1;
1675 data.compute_checksum = 0;
1677 /* FIXME - Passing vers_ts->tag here is wrong in the least number
1678 * of cases. Since we don't know whether vn_user was checked out
1679 * using a tag, we pass vers_ts->tag, which, assuming the user did
1680 * not specify a new TAG to -r, will be the branch we are on.
1682 * The only thing it is used for is to substitute in for the Name
1683 * RCS keyword, so in the error case, the patch fails to apply on
1684 * the client end and we end up resending the whole file.
1686 * At least, if we are keeping track of the tag vn_user came from,
1687 * I don't know where yet. -DRP
1689 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1690 vers_ts->vn_user, vers_ts->tag,
1691 vers_ts->options, RUN_TTY,
1692 patch_file_write, (void *) &data);
1695 error (1, errno, "cannot close %s", file1);
1697 if (retcode != 0 || ! data.final_nl)
1702 e = CVS_FOPEN (file2, "w");
1704 error (1, errno, "cannot open %s", file2);
1706 data.filename = file2;
1709 data.compute_checksum = 1;
1710 cvs_MD5Init (&data.context);
1712 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1713 vers_ts->vn_rcs, vers_ts->tag,
1714 vers_ts->options, RUN_TTY,
1715 patch_file_write, (void *) &data);
1718 error (1, errno, "cannot close %s", file2);
1720 if (retcode != 0 || ! data.final_nl)
1723 cvs_MD5Final (checksum, &data.context);
1731 /* If the client does not support the Rcs-diff command, we
1732 send a context diff, and the client must invoke patch.
1733 That approach was problematical for various reasons. The
1734 new approach only requires running diff in the server; the
1735 client can handle everything without invoking an external
1737 if (! rcs_diff_patches)
1739 /* We use -c, not -u, because that is what CVS has
1740 traditionally used. Kind of a moot point, now that
1741 Rcs-diff is preferred, so there is no point in making
1742 the compatibility issues worse. */
1743 diff_options = "-c";
1747 /* Now that diff is librarified, we could be passing -a if
1748 we wanted to. However, it is unclear to me whether we
1749 would want to. Does diff -a, in any significant
1750 percentage of cases, produce patches which are smaller
1751 than the files it is patching? I guess maybe text
1752 files with character sets which diff regards as
1753 'binary'. Conversely, do they tend to be much larger
1754 in the bad cases? This needs some more
1755 thought/investigation, I suspect. */
1757 diff_options = "-n";
1759 retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file);
1761 /* A retcode of 0 means no differences. 1 means some differences. */
1771 struct stat file2_info;
1773 /* Check to make sure the patch is really shorter */
1774 if (CVS_STAT (file2, &file2_info) < 0)
1775 error (1, errno, "could not stat %s", file2);
1776 if (CVS_STAT (finfo->file, file_info) < 0)
1777 error (1, errno, "could not stat %s", finfo->file);
1778 if (file2_info.st_size <= file_info->st_size)
1784 # define BINARY "Binary"
1785 char buf[sizeof BINARY];
1788 /* Check the diff output to make sure patch will be handle it. */
1789 e = CVS_FOPEN (finfo->file, "r");
1791 error (1, errno, "could not open diff output file %s",
1793 c = fread (buf, 1, sizeof BINARY - 1, e);
1795 if (strcmp (buf, BINARY) == 0)
1797 /* These are binary files. We could use diff -a, but
1798 patch can't handle that. */
1808 /* Stat the original RCS file, and then adjust it the way
1809 that RCS_checkout would. FIXME: This is an abstraction
1811 if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0)
1812 error (1, errno, "could not stat %s", vers_ts->srcfile->path);
1813 if (chmod (finfo->file,
1814 file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
1816 error (0, errno, "cannot change mode of file %s", finfo->file);
1818 && !fileattr_get (finfo->file, "_watched"))
1819 xchmod (finfo->file, 1);
1821 /* This stuff is just copied blindly from checkout_file. I
1822 don't really know what it does. */
1823 xvers_ts = Version_TS (finfo, options, tag, date,
1824 force_tag_match, 0);
1825 if (strcmp (xvers_ts->options, "-V4") == 0)
1826 xvers_ts->options[0] = '\0';
1828 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1829 xvers_ts->ts_user, xvers_ts->options,
1830 xvers_ts->tag, xvers_ts->date, NULL);
1832 if (CVS_STAT (finfo->file, file_info) < 0)
1833 error (1, errno, "could not stat %s", finfo->file);
1835 /* If this is really Update and not Checkout, record history. */
1836 if (strcmp (cvs_cmd_name, "update") == 0)
1837 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
1838 finfo->file, finfo->repository);
1840 freevers_ts (&xvers_ts);
1844 write_letter (finfo, 'P');
1849 int old_errno = errno; /* save errno value over the rename */
1851 if (isfile (backup))
1852 rename_file (backup, finfo->file);
1854 if (retcode != 0 && retcode != 1)
1855 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1856 "could not diff %s", finfo->fullname);
1862 if (unlink_file (backup) < 0
1863 && !existence_error (errno))
1864 error (0, errno, "cannot remove %s", backup);
1865 if (unlink_file (file1) < 0
1866 && !existence_error (errno))
1867 error (0, errno, "cannot remove %s", file1);
1868 if (unlink_file (file2) < 0
1869 && !existence_error (errno))
1870 error (0, errno, "cannot remove %s", file2);
1880 /* Write data to a file. Record whether the last byte written was a
1881 newline. Optionally compute a checksum. This is called by
1882 patch_file via RCS_checkout. */
1885 patch_file_write (callerdat, buffer, len)
1890 struct patch_file_data *data = (struct patch_file_data *) callerdat;
1892 if (fwrite (buffer, 1, len, data->fp) != len)
1893 error (1, errno, "cannot write %s", data->filename);
1895 data->final_nl = (buffer[len - 1] == '\n');
1897 if (data->compute_checksum)
1898 cvs_MD5Update (&data->context, (unsigned char *) buffer, len);
1901 #endif /* SERVER_SUPPORT */
1904 * Several of the types we process only print a bit of information consisting
1905 * of a single letter and the name.
1908 write_letter (finfo, letter)
1909 struct file_info *finfo;
1915 /* Big enough for "+updated" or any of its ilk. */
1924 /* We don't yet support tagged output except for "U". */
1930 sprintf (buf, "+%s", tag);
1931 cvs_output_tagged (buf, NULL);
1936 cvs_output_tagged ("text", buf);
1937 cvs_output_tagged ("fname", finfo->fullname);
1938 cvs_output_tagged ("newline", NULL);
1941 sprintf (buf, "-%s", tag);
1942 cvs_output_tagged (buf, NULL);
1951 * Do all the magic associated with a file which needs to be merged
1954 merge_file (finfo, vers)
1955 struct file_info *finfo;
1964 * The users currently modified file is moved to a backup file name
1965 * ".#filename.version", so that it will stay around for a few days
1966 * before being automatically removed by some cron daemon. The "version"
1967 * is the version of the file that the user was most up-to-date with
1970 backup = xmalloc (strlen (finfo->file)
1971 + strlen (vers->vn_user)
1972 + sizeof (BAKPREFIX)
1974 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1976 if (unlink_file (backup) && !existence_error (errno))
1977 error (0, errno, "unable to remove %s", backup);
1978 copy_file (finfo->file, backup);
1979 xchmod (finfo->file, 1);
1981 if (strcmp (vers->options, "-kb") == 0
1982 || wrap_merge_is_copy (finfo->file)
1983 || special_file_mismatch (finfo, NULL, vers->vn_rcs))
1985 /* For binary files, a merge is always a conflict. Same for
1986 files whose permissions or linkage do not match. We give the
1987 user the two files, and let them resolve it. It is possible
1988 that we should require a "touch foo" or similar step before
1989 we allow a checkin. */
1991 /* TODO: it may not always be necessary to regard a permission
1992 mismatch as a conflict. The working file and the RCS file
1993 have a common ancestor `A'; if the working file's permissions
1994 match A's, then it's probably safe to overwrite them with the
1995 RCS permissions. Only if the working file, the RCS file, and
1996 A all disagree should this be considered a conflict. But more
1997 thought needs to go into this, and in the meantime it is safe
1998 to treat any such mismatch as an automatic conflict. -twp */
2000 #ifdef SERVER_SUPPORT
2002 server_copy_file (finfo->file, finfo->update_dir,
2003 finfo->repository, backup);
2006 status = checkout_file (finfo, vers, 0, 1, 1);
2008 /* Is there a better term than "nonmergeable file"? What we
2009 really mean is, not something that CVS cannot or does not
2010 want to merge (there might be an external manual or
2011 automatic merge process). */
2012 error (0, 0, "nonmergeable file needs merge");
2013 error (0, 0, "revision %s from repository is now in %s",
2014 vers->vn_rcs, finfo->fullname);
2015 error (0, 0, "file from working directory is now in %s", backup);
2016 write_letter (finfo, 'C');
2018 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2024 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2025 vers->options, vers->vn_user, vers->vn_rcs);
2026 if (status != 0 && status != 1)
2028 error (0, status == -1 ? errno : 0,
2029 "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
2030 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2031 finfo->fullname, backup);
2032 rename_file (backup, finfo->file);
2037 if (strcmp (vers->options, "-V4") == 0)
2038 vers->options[0] = '\0';
2040 /* This file is the result of a merge, which means that it has
2041 been modified. We use a special timestamp string which will
2042 not compare equal to any actual timestamp. */
2048 (void) time (&last_register_time);
2049 cp = time_stamp (finfo->file);
2051 Register (finfo->entries, finfo->file, vers->vn_rcs,
2052 "Result of merge", vers->options, vers->tag,
2058 /* fix up the vers structure, in case it is used by join */
2061 /* FIXME: Throwing away the original revision info is almost
2062 certainly wrong -- what if join_rev1 is "BASE"? */
2063 if (vers->vn_user != NULL)
2064 free (vers->vn_user);
2065 vers->vn_user = xstrdup (vers->vn_rcs);
2068 #ifdef SERVER_SUPPORT
2069 /* Send the new contents of the file before the message. If we
2070 wanted to be totally correct, we would have the client write
2071 the message only after the file has safely been written. */
2074 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
2076 server_updated (finfo, vers, SERVER_MERGED,
2077 (mode_t) -1, (unsigned char *) NULL,
2078 (struct buffer *) NULL);
2082 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2083 xcmp on the temporary files without much hassle, I think. */
2084 if (!noexec && !xcmp (backup, finfo->file))
2086 cvs_output (finfo->fullname, 0);
2087 cvs_output (" already contains the differences between ", 0);
2088 cvs_output (vers->vn_user, 0);
2089 cvs_output (" and ", 0);
2090 cvs_output (vers->vn_rcs, 0);
2091 cvs_output ("\n", 1);
2093 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2101 error (0, 0, "conflicts found in %s", finfo->fullname);
2103 write_letter (finfo, 'C');
2105 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2109 else if (retcode == -1)
2111 error (1, errno, "fork failed while examining update of %s",
2116 write_letter (finfo, 'M');
2117 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2129 * Do all the magic associated with a file which needs to be joined
2130 * (reached via the -j option to checkout or update).
2133 * finfo File information about the destination file.
2134 * vers The Vers_TS structure for finfo.
2137 * join_rev1 From the command line.
2138 * join_rev2 From the command line.
2139 * server_active Natch.
2142 * 1. Is not called in client mode.
2145 join_file (finfo, vers)
2146 struct file_info *finfo;
2161 fprintf (stderr, "%s-> join_file(%s, %s%s%s%s, %s, %s)\n",
2164 vers->tag ? vers->tag : "",
2165 vers->tag ? " (" : "",
2166 vers->vn_rcs ? vers->vn_rcs : "",
2167 vers->tag ? ")" : "",
2168 join_rev1 ? join_rev1 : "",
2169 join_rev2 ? join_rev2 : "");
2176 /* Determine if we need to do anything at all. */
2177 if (vers->srcfile == NULL ||
2178 vers->srcfile->path == NULL)
2183 /* If only one join revision is specified, it becomes the second
2193 /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
2194 below about vn_user. */
2196 /* Convert the second revision, walking branches and dates. */
2197 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
2199 /* If this is a merge of two revisions, get the first revision.
2200 If only one join tag was specified, then the first revision is
2201 the greatest common ancestor of the second revision and the
2204 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL);
2207 /* Note that we use vn_rcs here, since vn_user may contain a
2208 special string such as "-nn". */
2209 if (vers->vn_rcs == NULL)
2211 else if (rev2 == NULL)
2213 /* This means that the file never existed on the branch.
2214 It does not mean that the file was removed on the
2215 branch: that case is represented by a dead rev2. If
2216 the file never existed on the branch, then we have
2217 nothing to merge, so we just return. */
2221 rev1 = gca (vers->vn_rcs, rev2);
2224 /* Handle a nonexistent or dead merge target. */
2225 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
2232 /* If the first revision doesn't exist either, then there is
2233 no change between the two revisions, so we don't do
2235 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2242 /* If we are merging two revisions, then the file was removed
2243 between the first revision and the second one. In this
2244 case we want to mark the file for removal.
2246 If we are merging one revision, then the file has been
2247 removed between the greatest common ancestor and the merge
2248 revision. From the perspective of the branch on to which
2249 we ar emerging, which may be the trunk, either 1) the file
2250 does not currently exist on the target, or 2) the file has
2251 not been modified on the target branch since the greatest
2252 common ancestor, or 3) the file has been modified on the
2253 target branch since the greatest common ancestor. In case
2254 1 there is nothing to do. In case 2 we mark the file for
2255 removal. In case 3 we have a conflict.
2257 Note that the handling is slightly different depending upon
2258 whether one or two join targets were specified. If two
2259 join targets were specified, we don't check whether the
2260 file was modified since a given point. My reasoning is
2261 that if you ask for an explicit merge between two tags,
2262 then you want to merge in whatever was changed between
2263 those two tags. If a file was removed between the two
2264 tags, then you want it to be removed. However, if you ask
2265 for a merge of a branch, then you want to merge in all
2266 changes which were made on the branch. If a file was
2267 removed on the branch, that is a change to the file. If
2268 the file was also changed on the main line, then that is
2269 also a change. These two changes--the file removal and the
2270 modification--must be merged. This is a conflict. */
2272 /* If the user file is dead, or does not exist, or has been
2273 marked for removal, then there is nothing to do. */
2274 if (vers->vn_user == NULL
2275 || vers->vn_user[0] == '-'
2276 || RCS_isdead (vers->srcfile, vers->vn_user))
2283 /* If the user file has been marked for addition, or has been
2284 locally modified, then we have a conflict which we can not
2285 resolve. No_Difference will already have been called in
2286 this case, so comparing the timestamps is sufficient to
2287 determine whether the file is locally modified. */
2288 if (strcmp (vers->vn_user, "0") == 0
2289 || (vers->ts_user != NULL
2290 && strcmp (vers->ts_user, vers->ts_rcs) != 0))
2294 "file %s is locally modified, but has been removed in revision %s as of %s",
2295 finfo->fullname, jrev2, jdate2);
2298 "file %s is locally modified, but has been removed in revision %s",
2299 finfo->fullname, jrev2);
2301 /* FIXME: Should we arrange to return a non-zero exit
2310 /* If only one join tag was specified, and the user file has
2311 been changed since the greatest common ancestor (rev1),
2312 then there is a conflict we can not resolve. See above for
2314 if (join_rev2 == NULL
2315 && strcmp (rev1, vers->vn_user) != 0)
2319 "file %s has been modified, but has been removed in revision %s as of %s",
2320 finfo->fullname, jrev2, jdate2);
2323 "file %s has been modified, but has been removed in revision %s",
2324 finfo->fullname, jrev2);
2326 /* FIXME: Should we arrange to return a non-zero exit
2338 /* The user file exists and has not been modified. Mark it
2339 for removal. FIXME: If we are doing a checkout, this has
2340 the effect of first checking out the file, and then
2341 removing it. It would be better to just register the
2344 The same goes for a removal then an add. e.g.
2345 cvs up -rbr -jbr2 could remove and readd the same file
2347 /* save the rev since server_updated might invalidate it */
2348 mrev = xmalloc (strlen (vers->vn_user) + 2);
2349 sprintf (mrev, "-%s", vers->vn_user);
2350 #ifdef SERVER_SUPPORT
2353 server_scratch (finfo->file);
2354 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
2355 (unsigned char *) NULL, (struct buffer *) NULL);
2358 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
2359 vers->options, vers->tag, vers->date, vers->ts_conflict);
2361 /* We need to check existence_error here because if we are
2362 running as the server, and the file is up to date in the
2363 working directory, the client will not have sent us a copy. */
2364 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
2365 error (0, errno, "cannot remove file %s", finfo->fullname);
2366 #ifdef SERVER_SUPPORT
2368 server_checked_in (finfo->file, finfo->update_dir,
2372 error (0, 0, "scheduling %s for removal", finfo->fullname);
2377 /* If the two merge revisions are the same, then there is nothing
2378 * to do. This needs to be checked before the rev2 == up-to-date base
2379 * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
2380 * "already contains the changes between <rev1> and <rev1>" message.
2382 if (rev1 && strcmp (rev1, rev2) == 0)
2389 /* If we know that the user file is up-to-date, then it becomes an
2390 * optimization to skip the merge when rev2 is the same as the base
2391 * revision. i.e. we know that diff3(file2,file1,file2) will produce
2394 if (vers->vn_user != NULL && vers->ts_user != NULL
2395 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2396 && strcmp (rev2, vers->vn_user) == 0)
2400 cvs_output (finfo->fullname, 0);
2401 cvs_output (" already contains the differences between ", 0);
2402 cvs_output (rev1 ? rev1 : "creation", 0);
2403 cvs_output (" and ", 0);
2404 cvs_output (rev2, 0);
2405 cvs_output ("\n", 1);
2415 /* If rev1 is dead or does not exist, then the file was added
2416 between rev1 and rev2. */
2417 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2423 /* If the file does not exist in the working directory, then
2424 we can just check out the new revision and mark it for
2426 if (vers->vn_user == NULL)
2428 char *saved_options = options;
2431 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
2433 /* Reset any keyword expansion option. Otherwise, when a
2434 command like `cvs update -kk -jT1 -jT2' creates a new file
2435 (because a file had the T2 tag, but not T1), the subsequent
2436 commit of that just-added file effectively would set the
2437 admin `-kk' option for that file in the repository. */
2440 /* FIXME: If checkout_file fails, we should arrange to
2441 return a non-zero exit status. */
2442 status = checkout_file (finfo, xvers, 1, 0, 1);
2443 options = saved_options;
2445 freevers_ts (&xvers);
2450 /* The file currently exists in the working directory, so we
2451 have a conflict which we can not resolve. Note that this
2452 is true even if the file is marked for addition or removal. */
2456 "file %s exists, but has been added in revision %s as of %s",
2457 finfo->fullname, jrev2, jdate2);
2460 "file %s exists, but has been added in revision %s",
2461 finfo->fullname, jrev2);
2466 /* If there is no working file, then we can't do the merge. */
2467 if (vers->vn_user == NULL || vers->vn_user[0] == '-')
2474 "file %s does not exist, but is present in revision %s as of %s",
2475 finfo->fullname, jrev2, jdate2);
2478 "file %s does not exist, but is present in revision %s",
2479 finfo->fullname, jrev2);
2481 /* FIXME: Should we arrange to return a non-zero exit status? */
2486 #ifdef SERVER_SUPPORT
2487 if (server_active && !isreadable (finfo->file))
2490 /* The file is up to date. Need to check out the current contents. */
2491 /* FIXME - see the FIXME comment above the call to RCS_checkout in the
2492 * patch_file function.
2494 retcode = RCS_checkout (vers->srcfile, finfo->file,
2495 vers->vn_user, vers->tag,
2496 (char *) NULL, RUN_TTY,
2497 (RCSCHECKOUTPROC) NULL, (void *) NULL);
2500 "failed to check out %s file", finfo->fullname);
2505 * The users currently modified file is moved to a backup file name
2506 * ".#filename.version", so that it will stay around for a few days
2507 * before being automatically removed by some cron daemon. The "version"
2508 * is the version of the file that the user was most up-to-date with
2511 backup = xmalloc (strlen (finfo->file)
2512 + strlen (vers->vn_user)
2513 + sizeof (BAKPREFIX)
2515 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
2517 if (unlink_file (backup) < 0
2518 && !existence_error (errno))
2519 error (0, errno, "cannot remove %s", backup);
2520 copy_file (finfo->file, backup);
2521 xchmod (finfo->file, 1);
2523 t_options = vers->options;
2525 if (*t_options == '\0')
2526 t_options = "-kk"; /* to ignore keyword expansions */
2529 /* If the source of the merge is the same as the working file
2530 revision, then we can just RCS_checkout the target (no merging
2531 as such). In the text file case, this is probably quite
2532 similar to the RCS_merge, but in the binary file case,
2533 RCS_merge gives all kinds of trouble. */
2534 if (vers->vn_user != NULL
2535 && strcmp (rev1, vers->vn_user) == 0
2536 /* See comments above about how No_Difference has already been
2538 && vers->ts_user != NULL
2539 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2541 /* Avoid this in the text file case. See below for why.
2543 && (strcmp (t_options, "-kb") == 0
2544 || wrap_merge_is_copy (finfo->file)))
2546 /* FIXME: Verify my comment below:
2548 * RCS_merge does nothing with keywords. It merges the changes between
2549 * two revisions without expanding the keywords (it might expand in
2550 * -kk mode before computing the diff between rev1 and rev2 - I'm not
2551 * sure). In other words, the keyword lines in the current work file
2554 * Therfore, checking out the destination revision (rev2) is probably
2555 * incorrect in the text case since we should see the keywords that were
2556 * substituted into the original file at the time it was checked out
2557 * and not the keywords from rev2.
2559 * Also, it is safe to pass in NULL for nametag since we know no
2560 * substitution is happening during the binary mode checkout.
2562 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL, t_options,
2563 RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0 )
2568 /* OK, this is really stupid. RCS_checkout carefully removes
2569 write permissions, and we carefully put them back. But
2570 until someone gets around to fixing it, that seems like the
2571 easiest way to get what would seem to be the right mode.
2572 I don't check CVSWRITE or _watched; I haven't thought about
2573 that in great detail, but it seems like a watched file should
2574 be checked out (writable) after a merge. */
2575 xchmod (finfo->file, 1);
2577 /* Traditionally, the text file case prints a whole bunch of
2578 scary looking and verbose output which fails to tell the user
2579 what is really going on (it gives them rev1 and rev2 but doesn't
2580 indicate in any way that rev1 == vn_user). I think just a
2581 simple "U foo" is good here; it seems analogous to the case in
2582 which the file was added on the branch in terms of what to
2584 write_letter (finfo, 'U');
2586 else if (strcmp (t_options, "-kb") == 0
2587 || wrap_merge_is_copy (finfo->file)
2588 || special_file_mismatch (finfo, rev1, rev2))
2590 /* We are dealing with binary files, or files with a
2591 permission/linkage mismatch (this second case only occurs when
2592 PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
2593 need to take place. This is a conflict. We give the user
2594 the two files, and let them resolve it. It is possible
2595 that we should require a "touch foo" or similar step before
2596 we allow a checkin. */
2597 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL,
2598 t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
2603 /* OK, this is really stupid. RCS_checkout carefully removes
2604 write permissions, and we carefully put them back. But
2605 until someone gets around to fixing it, that seems like the
2606 easiest way to get what would seem to be the right mode.
2607 I don't check CVSWRITE or _watched; I haven't thought about
2608 that in great detail, but it seems like a watched file should
2609 be checked out (writable) after a merge. */
2610 xchmod (finfo->file, 1);
2612 /* Hmm. We don't give them REV1 anywhere. I guess most people
2613 probably don't have a 3-way merge tool for the file type in
2614 question, and might just get confused if we tried to either
2615 provide them with a copy of the file from REV1, or even just
2616 told them what REV1 is so they can get it themself, but it
2617 might be worth thinking about. */
2618 /* See comment in merge_file about the "nonmergeable file"
2620 error (0, 0, "nonmergeable file needs merge");
2621 error (0, 0, "revision %s from repository is now in %s",
2622 rev2, finfo->fullname);
2623 error (0, 0, "file from working directory is now in %s", backup);
2624 write_letter (finfo, 'C');
2627 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2628 t_options, rev1, rev2);
2634 error (0, status == -1 ? errno : 0,
2635 "could not merge revision %s of %s", rev2, finfo->fullname);
2636 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2637 finfo->fullname, backup);
2638 rename_file (backup, finfo->file);
2641 else /* status == 0 */
2643 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2644 xcmp on the temporary files without much hassle, I think. */
2645 if (!noexec && !xcmp (backup, finfo->file))
2649 cvs_output (finfo->fullname, 0);
2650 cvs_output (" already contains the differences between ", 0);
2651 cvs_output (rev1, 0);
2652 cvs_output (" and ", 0);
2653 cvs_output (rev2, 0);
2654 cvs_output ("\n", 1);
2657 /* and skip the registering and sending the new file since it
2658 * hasn't been updated.
2664 /* The file has changed, but if we just checked it out it may
2665 still have the same timestamp it did when it was first
2666 registered above in checkout_file. We register it again with a
2667 dummy timestamp to make sure that later runs of CVS will
2668 recognize that it has changed.
2670 We don't actually need to register again if we called
2671 RCS_checkout above, and we aren't running as the server.
2672 However, that is not the normal case, and calling Register
2673 again won't cost much in that case. */
2679 (void) time (&last_register_time);
2680 cp = time_stamp (finfo->file);
2682 Register (finfo->entries, finfo->file,
2683 vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge",
2684 vers->options, vers->tag, vers->date, cp);
2689 #ifdef SERVER_SUPPORT
2692 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
2694 server_updated (finfo, vers, SERVER_MERGED,
2695 (mode_t) -1, (unsigned char *) NULL,
2696 (struct buffer *) NULL);
2709 * Report whether revisions REV1 and REV2 of FINFO agree on:
2712 * . major and minor device numbers
2716 * If either REV1 or REV2 is NULL, the working copy is used instead.
2718 * Return 1 if the files differ on these data.
2722 special_file_mismatch (finfo, rev1, rev2)
2723 struct file_info *finfo;
2727 #ifdef PRESERVE_PERMISSIONS_SUPPORT
2731 uid_t rev1_uid, rev2_uid;
2732 gid_t rev1_gid, rev2_gid;
2733 mode_t rev1_mode, rev2_mode;
2734 unsigned long dev_long;
2735 dev_t rev1_dev, rev2_dev;
2736 char *rev1_symlink = NULL;
2737 char *rev2_symlink = NULL;
2738 List *rev1_hardlinks = NULL;
2739 List *rev2_hardlinks = NULL;
2740 int check_uids, check_gids, check_modes;
2743 /* If we don't care about special file info, then
2744 don't report a mismatch in any case. */
2745 if (!preserve_perms)
2748 /* When special_file_mismatch is called from No_Difference, the
2749 RCS file has been only partially parsed. We must read the
2750 delta tree in order to compare special file info recorded in
2751 the delta nodes. (I think this is safe. -twp) */
2752 if (finfo->rcs->flags & PARTIAL)
2753 RCS_reparsercsfile (finfo->rcs, NULL, NULL);
2755 check_uids = check_gids = check_modes = 1;
2757 /* Obtain file information for REV1. If this is null, then stat
2758 finfo->file and use that info. */
2759 /* If a revision does not know anything about its status,
2760 then presumably it doesn't matter, and indicates no conflict. */
2764 if (islink (finfo->file))
2765 rev1_symlink = xreadlink (finfo->file);
2768 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2769 if (CVS_LSTAT (finfo->file, &sb) < 0)
2770 error (1, errno, "could not get file information for %s",
2772 rev1_uid = sb.st_uid;
2773 rev1_gid = sb.st_gid;
2774 rev1_mode = sb.st_mode;
2775 if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
2776 rev1_dev = sb.st_rdev;
2778 error (1, 0, "cannot handle device files on this system (%s)",
2782 rev1_hardlinks = list_linked_files_on_disk (finfo->file);
2786 n = findnode (finfo->rcs->versions, rev1);
2789 n = findnode (vp->other_delta, "symlink");
2791 rev1_symlink = xstrdup (n->data);
2794 n = findnode (vp->other_delta, "owner");
2796 check_uids = 0; /* don't care */
2798 rev1_uid = strtoul (n->data, NULL, 10);
2800 n = findnode (vp->other_delta, "group");
2802 check_gids = 0; /* don't care */
2804 rev1_gid = strtoul (n->data, NULL, 10);
2806 n = findnode (vp->other_delta, "permissions");
2808 check_modes = 0; /* don't care */
2810 rev1_mode = strtoul (n->data, NULL, 8);
2812 n = findnode (vp->other_delta, "special");
2814 rev1_mode |= S_IFREG;
2817 /* If the size of `ftype' changes, fix the sscanf call also */
2819 if (sscanf (n->data, "%15s %lu", ftype,
2821 error (1, 0, "%s:%s has bad `special' newphrase %s",
2822 finfo->file, rev1, (char *)n->data);
2823 rev1_dev = dev_long;
2824 if (strcmp (ftype, "character") == 0)
2825 rev1_mode |= S_IFCHR;
2826 else if (strcmp (ftype, "block") == 0)
2827 rev1_mode |= S_IFBLK;
2829 error (0, 0, "%s:%s unknown file type `%s'",
2830 finfo->file, rev1, ftype);
2833 rev1_hardlinks = vp->hardlinks;
2834 if (rev1_hardlinks == NULL)
2835 rev1_hardlinks = getlist();
2839 /* Obtain file information for REV2. */
2842 if (islink (finfo->file))
2843 rev2_symlink = xreadlink (finfo->file);
2846 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2847 if (CVS_LSTAT (finfo->file, &sb) < 0)
2848 error (1, errno, "could not get file information for %s",
2850 rev2_uid = sb.st_uid;
2851 rev2_gid = sb.st_gid;
2852 rev2_mode = sb.st_mode;
2853 if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
2854 rev2_dev = sb.st_rdev;
2856 error (1, 0, "cannot handle device files on this system (%s)",
2860 rev2_hardlinks = list_linked_files_on_disk (finfo->file);
2864 n = findnode (finfo->rcs->versions, rev2);
2867 n = findnode (vp->other_delta, "symlink");
2869 rev2_symlink = xstrdup (n->data);
2872 n = findnode (vp->other_delta, "owner");
2874 check_uids = 0; /* don't care */
2876 rev2_uid = strtoul (n->data, NULL, 10);
2878 n = findnode (vp->other_delta, "group");
2880 check_gids = 0; /* don't care */
2882 rev2_gid = strtoul (n->data, NULL, 10);
2884 n = findnode (vp->other_delta, "permissions");
2886 check_modes = 0; /* don't care */
2888 rev2_mode = strtoul (n->data, NULL, 8);
2890 n = findnode (vp->other_delta, "special");
2892 rev2_mode |= S_IFREG;
2895 /* If the size of `ftype' changes, fix the sscanf call also */
2897 if (sscanf (n->data, "%15s %lu", ftype,
2899 error (1, 0, "%s:%s has bad `special' newphrase %s",
2900 finfo->file, rev2, (char *)n->data);
2901 rev2_dev = dev_long;
2902 if (strcmp (ftype, "character") == 0)
2903 rev2_mode |= S_IFCHR;
2904 else if (strcmp (ftype, "block") == 0)
2905 rev2_mode |= S_IFBLK;
2907 error (0, 0, "%s:%s unknown file type `%s'",
2908 finfo->file, rev2, ftype);
2911 rev2_hardlinks = vp->hardlinks;
2912 if (rev2_hardlinks == NULL)
2913 rev2_hardlinks = getlist();
2917 /* Check the user/group ownerships and file permissions, printing
2918 an error for each mismatch found. Return 0 if all characteristics
2919 matched, and 1 otherwise. */
2923 /* Compare symlinks first, since symlinks are simpler (don't have
2924 any other characteristics). */
2925 if (rev1_symlink != NULL && rev2_symlink == NULL)
2927 error (0, 0, "%s is a symbolic link",
2928 (rev1 == NULL ? "working file" : rev1));
2931 else if (rev1_symlink == NULL && rev2_symlink != NULL)
2933 error (0, 0, "%s is a symbolic link",
2934 (rev2 == NULL ? "working file" : rev2));
2937 else if (rev1_symlink != NULL)
2938 result = (strcmp (rev1_symlink, rev2_symlink) == 0);
2941 /* Compare user ownership. */
2942 if (check_uids && rev1_uid != rev2_uid)
2944 error (0, 0, "%s: owner mismatch between %s and %s",
2946 (rev1 == NULL ? "working file" : rev1),
2947 (rev2 == NULL ? "working file" : rev2));
2951 /* Compare group ownership. */
2952 if (check_gids && rev1_gid != rev2_gid)
2954 error (0, 0, "%s: group mismatch between %s and %s",
2956 (rev1 == NULL ? "working file" : rev1),
2957 (rev2 == NULL ? "working file" : rev2));
2961 /* Compare permissions. */
2963 (rev1_mode & 07777) != (rev2_mode & 07777))
2965 error (0, 0, "%s: permission mismatch between %s and %s",
2967 (rev1 == NULL ? "working file" : rev1),
2968 (rev2 == NULL ? "working file" : rev2));
2972 /* Compare device file characteristics. */
2973 if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
2975 error (0, 0, "%s: %s and %s are different file types",
2977 (rev1 == NULL ? "working file" : rev1),
2978 (rev2 == NULL ? "working file" : rev2));
2981 else if (S_ISBLK (rev1_mode))
2983 if (rev1_dev != rev2_dev)
2985 error (0, 0, "%s: device numbers of %s and %s do not match",
2987 (rev1 == NULL ? "working file" : rev1),
2988 (rev2 == NULL ? "working file" : rev2));
2993 /* Compare hard links. */
2994 if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
2996 error (0, 0, "%s: hard linkage of %s and %s do not match",
2998 (rev1 == NULL ? "working file" : rev1),
2999 (rev2 == NULL ? "working file" : rev2));
3004 if (rev1_symlink != NULL)
3005 free (rev1_symlink);
3006 if (rev2_symlink != NULL)
3007 free (rev2_symlink);
3008 if (rev1_hardlinks != NULL)
3009 dellist (&rev1_hardlinks);
3010 if (rev2_hardlinks != NULL)
3011 dellist (&rev2_hardlinks);
3024 return join_rev1 != NULL;