2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * "update" updates the version in the present directory with respect to the RCS
14 * repository. The present version must have been created by "checkout". The
15 * user can keep up-to-date by calling "update" whenever he feels like it.
17 * The present version can be committed by "commit", but this keeps the version
20 * Arguments following the options are taken to be file names to be updated,
21 * rather than updating the entire directory.
23 * Modified or non-existent RCS files are checked out and reported as U
26 * Modified user files are reported as M <user_file>. If both the RCS file and
27 * the user file have been modified, the user file is replaced by the result
28 * of rcsmerge, and a backup file is written for the user in .#file.version.
29 * If this throws up irreconcilable differences, the file is reported as C
30 * <user_file>, and as M <user_file> otherwise.
32 * Files added but not yet committed are reported as A <user_file>. Files
33 * removed but not yet committed are reported as R <user_file>.
35 * If the current directory contains subdirectories that hold concurrent
36 * versions, these are updated too. If the -d option was specified, new
37 * directories added to the repository are automatically created and updated
56 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
57 int adding, int merging, int update_server));
59 static void checkout_to_buffer PROTO ((void *, const char *, size_t));
60 static int patch_file PROTO ((struct file_info *finfo,
62 int *docheckout, struct stat *file_info,
63 unsigned char *checksum));
64 static void patch_file_write PROTO ((void *, const char *, size_t));
65 #endif /* SERVER_SUPPORT */
66 static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
67 static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers));
68 static Dtype update_dirent_proc PROTO ((void *callerdat, const char *dir,
69 const char *repository,
70 const char *update_dir,
72 static int update_dirleave_proc PROTO ((void *callerdat, const char *dir,
73 int err, const char *update_dir,
75 static int update_fileproc PROTO ((void *callerdat, struct file_info *));
76 static int update_filesdone_proc PROTO ((void *callerdat, int err,
77 const char *repository,
78 const char *update_dir,
80 #ifdef PRESERVE_PERMISSIONS_SUPPORT
81 static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *));
83 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
85 static char *options = NULL;
86 static char *tag = NULL;
87 static char *date = NULL;
88 /* This is a bit of a kludge. We call WriteTag at the beginning
89 before we know whether nonbranch is set or not. And then at the
90 end, once we have the right value for nonbranch, we call WriteTag
91 again. I don't know whether the first call is necessary or not.
92 rewrite_tag is nonzero if we are going to have to make that second
94 static int rewrite_tag;
97 /* If we set the tag or date for a subdirectory, we use this to undo
98 the setting. See update_dirent_proc. */
99 static char *tag_update_dir;
101 static char *join_rev1, *date_rev1;
102 static char *join_rev2, *date_rev2;
103 static int aflag = 0;
104 static int toss_local_changes = 0;
105 static int force_tag_match = 1;
106 static int pull_template = 0;
107 static int update_build_dirs = 0;
108 static int update_prune_dirs = 0;
109 static int pipeout = 0;
110 #ifdef SERVER_SUPPORT
111 static int patches = 0;
112 static int rcs_diff_patches = 0;
114 static List *ignlist = (List *) NULL;
115 static time_t last_register_time;
116 static const char *const update_usage[] =
118 "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n",
119 " [-I ign] [-W spec] [files...]\n",
120 "\t-A\tReset any sticky tags/date/kopts.\n",
121 "\t-P\tPrune empty directories.\n",
122 "\t-C\tOverwrite locally modified files with clean repository copies.\n",
123 "\t-d\tBuild directories, like checkout does.\n",
124 "\t-f\tForce a head revision match if tag/date not found.\n",
125 "\t-l\tLocal directory only, no recursion.\n",
126 "\t-R\tProcess directories recursively.\n",
127 "\t-p\tSend updates to standard output (avoids stickiness).\n",
128 "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
129 "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
130 "\t-D date\tSet date to update from (is sticky).\n",
131 "\t-j rev\tMerge in changes made between current revision and rev.\n",
132 "\t-I ign\tMore files to ignore (! to reset).\n",
133 "\t-W spec\tWrappers specification line.\n",
134 "\t-T\tCreate CVS/Template.\n",
135 "(Specify the --help global option for a list of other help options)\n",
140 * update is the argv,argc based front end for arg parsing
148 int local = 0; /* recursive by default */
149 int which; /* where to look for files and dirs */
150 int xpull_template = 0;
153 usage (update_usage);
160 while ((c = getopt (argc, argv, "+ApCPflRQTqduk:r:D:j:I:W:")) != -1)
168 toss_local_changes = 1;
174 wrap_add (optarg, 0);
179 options = RCS_check_kflag (optarg);
189 /* The CVS 1.5 client sends these options (in addition to
190 Global_option requests), so we must ignore them. */
193 "-q or -Q must be specified before \"%s\"",
200 update_build_dirs = 1;
209 if (date) free (date);
210 date = Make_Date (optarg);
213 update_prune_dirs = 1;
217 noexec = 1; /* so no locks will be created */
221 error (1, 0, "only two -j options can be specified");
228 #ifdef SERVER_SUPPORT
232 rcs_diff_patches = server_use_rcs_diff ();
236 usage (update_usage);
240 usage (update_usage);
247 #ifdef CLIENT_SUPPORT
248 if (current_parsed_root->isremote)
252 /* The first pass does the regular update. If we receive at least
253 one patch which failed, we do a second pass and just fetch
254 those files whose patches failed. */
264 if (update_build_dirs)
268 if (!force_tag_match)
272 if (toss_local_changes)
274 if (update_prune_dirs)
276 client_prune_dirs = update_prune_dirs;
277 option_with_arg ("-r", tag);
278 if (options && options[0] != '\0')
281 client_senddate (date);
283 option_with_arg ("-j", join_rev1);
285 option_with_arg ("-j", join_rev2);
288 if (failed_patches_count == 0)
290 unsigned int flags = 0;
292 /* If the server supports the command "update-patches", that
293 means that it knows how to handle the -u argument to update,
294 which means to send patches instead of complete files.
296 We don't send -u if failed_patches != NULL, so that the
297 server doesn't try to send patches which will just fail
298 again. At least currently, the client also clobbers the
299 file and tells the server it is lost, which also will get
300 a full file instead of a patch, but it seems clean to omit
302 if (supported_request ("update-patches"))
307 if (update_build_dirs)
308 flags |= SEND_BUILD_DIRS;
310 if (toss_local_changes) {
311 flags |= SEND_NO_CONTENTS;
312 flags |= BACKUP_MODIFIED_FILES;
315 /* If noexec, probably could be setting SEND_NO_CONTENTS.
316 Same caveats as for "cvs status" apply. */
318 send_files (argc, argv, local, aflag, flags);
319 send_file_names (argc, argv, SEND_EXPAND_WILD);
325 (void) printf ("%s client: refetching unpatchable files\n",
328 if (toplevel_wd != NULL
329 && CVS_CHDIR (toplevel_wd) < 0)
331 error (1, errno, "could not chdir to %s", toplevel_wd);
336 for (i = 0; i < failed_patches_count; i++)
337 if (unlink_file (failed_patches[i]) < 0
338 && !existence_error (errno))
339 error (0, errno, "cannot remove %s",
341 send_files (failed_patches_count, failed_patches, local,
342 aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
343 send_file_names (failed_patches_count, failed_patches, 0);
344 free_names (&failed_patches_count, failed_patches);
347 send_to_server ("update\012", 0);
349 status = get_responses_and_close ();
351 /* If there are any conflicts, the server will return a
352 non-zero exit status. If any patches failed, we still
353 want to run the update again. We use a pass count to
354 avoid an endless loop. */
356 /* Notes: (1) assuming that status != 0 implies a
357 potential conflict is the best we can cleanly do given
358 the current protocol. I suppose that trying to
359 re-fetch in cases where there was a more serious error
360 is probably more or less harmless, but it isn't really
361 ideal. (2) it would be nice to have a testsuite case for the
362 conflict-and-patch-failed case. */
365 && (failed_patches_count == 0 || pass > 1))
367 if (failed_patches_count > 0)
368 free_names (&failed_patches_count, failed_patches);
373 } while (failed_patches_count > 0);
380 tag_check_valid (tag, argc, argv, local, aflag, "");
381 if (join_rev1 != NULL)
382 tag_check_valid_join (join_rev1, argc, argv, local, aflag, "");
383 if (join_rev2 != NULL)
384 tag_check_valid_join (join_rev2, argc, argv, local, aflag, "");
387 * If we are updating the entire directory (for real) and building dirs
388 * as we go, we make sure there is no static entries file and write the
389 * tag file as appropriate
391 if (argc <= 0 && !pipeout)
393 if (update_build_dirs)
395 if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
396 error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
397 #ifdef SERVER_SUPPORT
400 char *repos = Name_Repository (NULL, NULL);
401 server_clear_entstat (".", repos);
407 /* keep the CVS/Tag file current with the specified arguments */
408 if (aflag || tag || date)
410 char *repos = Name_Repository (NULL, NULL);
411 WriteTag ((char *) NULL, tag, date, 0, ".", repos);
418 /* look for files/dirs locally and in the repository */
419 which = W_LOCAL | W_REPOS;
421 /* look in the attic too if a tag or date is specified */
422 if (tag != NULL || date != NULL || joining())
425 /* call the command line interface */
426 err = do_update (argc, argv, options, tag, date, force_tag_match,
427 local, update_build_dirs, aflag, update_prune_dirs,
428 pipeout, which, join_rev1, join_rev2, (char *) NULL,
429 xpull_template, (char *) NULL);
431 /* free the space Make_Date allocated if necessary */
441 * Command line interface to update (used by checkout)
444 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
445 xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir,
446 xpull_template, repository)
461 char *preload_update_dir;
468 /* fill in the statics */
472 force_tag_match = xforce;
473 update_build_dirs = xbuild;
475 update_prune_dirs = xprune;
477 pull_template = xpull_template;
479 /* setup the join support */
480 join_rev1 = xjoin_rev1;
481 join_rev2 = xjoin_rev2;
482 if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
485 date_rev1 = Make_Date (cp);
488 date_rev1 = (char *) NULL;
489 if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
492 date_rev2 = Make_Date (cp);
495 date_rev2 = (char *) NULL;
497 #ifdef PRESERVE_PERMISSIONS_SUPPORT
500 /* We need to do an extra recursion, bleah. It's to make sure
501 that we know as much as possible about file linkage. */
502 hardlist = getlist();
503 working_dir = xgetwd(); /* save top-level working dir */
505 /* FIXME-twp: the arguments to start_recursion make me dizzy. This
506 function call was copied from the update_fileproc call that
507 follows it; someone should make sure that I did it right. */
508 err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL,
509 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
510 argc, argv, local, which, aflag, CVS_LOCK_READ,
511 preload_update_dir, 1, (char *) NULL);
515 /* FIXME-twp: at this point we should walk the hardlist
516 and update the `links' field of each hardlink_info struct
517 to list the files that are linked on dist. That would make
518 it easier & more efficient to compare the disk linkage with
519 the repository linkage (a simple strcmp). */
523 /* call the recursion processor */
524 err = start_recursion (update_fileproc, update_filesdone_proc,
525 update_dirent_proc, update_dirleave_proc, NULL,
526 argc, argv, local, which, aflag, CVS_LOCK_READ,
527 preload_update_dir, 1, repository);
529 /* see if we need to sleep before returning to avoid time-stamp races */
530 if (!server_active && 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 if (!really_quiet && !server_active)
687 (void) printf ("(Locally modified %s moved to %s)\n",
688 finfo->file, bakname);
691 /* The locally modified file is still present, but
692 it will be overwritten by the repository copy
695 retval = checkout_file (finfo, vers, 0, 0, 1);
699 if (vers->ts_conflict)
701 if (file_has_markers (finfo))
703 write_letter (finfo, 'C');
708 /* Reregister to clear conflict flag. */
709 Register (finfo->entries, finfo->file,
710 vers->vn_rcs, vers->ts_rcs,
711 vers->options, vers->tag,
712 vers->date, (char *)0);
716 write_letter (finfo, 'M');
719 case T_PATCH: /* needs patch */
720 #ifdef SERVER_SUPPORT
724 struct stat file_info;
725 unsigned char checksum[16];
727 retval = patch_file (finfo,
729 &file_info, checksum);
732 if (server_active && retval == 0)
733 server_updated (finfo, vers,
737 file_info.st_mode, checksum,
738 (struct buffer *) NULL);
743 /* If we're not running as a server, just check the
744 file out. It's simpler and faster than producing
745 and applying patches. */
747 case T_CHECKOUT: /* needs checkout */
748 retval = checkout_file (finfo, vers, 0, 0, 1);
750 case T_ADDED: /* added but not committed */
751 write_letter (finfo, 'A');
754 case T_REMOVED: /* removed but not committed */
755 write_letter (finfo, 'R');
758 case T_REMOVE_ENTRY: /* needs to be un-registered */
759 retval = scratch_file (finfo, vers);
761 default: /* can't ever happen :-) */
763 "unknown file status %d for file %s", status, finfo->file);
769 /* only try to join if things have gone well thus far */
770 if (retval == 0 && join_rev1)
771 join_file (finfo, vers);
773 /* if this directory has an ignore list, add this file to it */
774 if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
780 p->key = xstrdup (finfo->file);
781 if (addnode (ignlist, p) != 0)
791 static void update_ignproc PROTO ((const char *, const char *));
794 update_ignproc (file, dir)
798 struct file_info finfo;
801 memset (&finfo, 0, sizeof (finfo));
803 finfo.update_dir = dir;
805 tmp = xstrdup (file);
808 tmp = xmalloc (strlen (file) + strlen (dir) + 10);
814 finfo.fullname = tmp;
815 write_letter (&finfo, '?');
823 update_filesdone_proc (callerdat, err, repository, update_dir, entries)
826 const char *repository;
827 const char *update_dir;
832 WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
836 /* if this directory has an ignore list, process it then free it */
839 ignore_files (ignlist, entries, update_dir, update_ignproc);
843 /* Clean up CVS admin dirs if we are export */
844 if (strcmp (cvs_cmd_name, "export") == 0)
846 /* I'm not sure the existence_error is actually possible (except
847 in cases where we really should print a message), but since
848 this code used to ignore all errors, I'll play it safe. */
849 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
850 error (0, errno, "cannot remove %s directory", CVSADM);
852 else if (!server_active && !pipeout)
854 /* If there is no CVS/Root file, add one */
855 if (!isfile (CVSADM_ROOT))
856 Create_Root ((char *) NULL, current_parsed_root->original);
865 * update_dirent_proc () is called back by the recursion processor before a
866 * sub-directory is processed for update. In this case, update_dirent proc
867 * will probably create the directory unless -d isn't specified and this is a
868 * new directory. A return code of 0 indicates the directory should be
869 * processed by the recursion code. A return of non-zero indicates the
870 * recursion code should skip this directory.
873 update_dirent_proc (callerdat, dir, repository, update_dir, entries)
876 const char *repository;
877 const char *update_dir;
880 if (ignore_directory (update_dir))
882 /* print the warm fuzzy message */
884 error (0, 0, "Ignoring %s", update_dir);
890 /* if we aren't building dirs, blow it off */
891 if (!update_build_dirs)
894 /* Various CVS administrators are in the habit of removing
895 the repository directory for things they don't want any
896 more. I've even been known to do it myself (on rare
897 occasions). Not the usual recommended practice, but we
898 want to try to come up with some kind of
899 reasonable/documented/sensible behavior. Generally
900 the behavior is to just skip over that directory (see
901 dirs test in sanity.sh; the case which reaches here
902 is when update -d is specified, and the working directory
903 is gone but the subdirectory is still mentioned in
905 /* In the remote case, the client should refrain from
906 sending us the directory in the first place. So we
907 want to continue to give an error, so clients make
909 if (!server_active && !isdir (repository))
914 /* ignore the missing dir if -n is specified */
915 error (0, 0, "New directory `%s' -- ignored", update_dir);
920 /* otherwise, create the dir and appropriate adm files */
922 /* If no tag or date were specified on the command line,
923 and we're not using -A, we want the subdirectory to use
924 the tag and date, if any, of the current directory.
925 That way, update -d will work correctly when working on
928 We use TAG_UPDATE_DIR to undo the tag setting in
929 update_dirleave_proc. If we did not do this, we would
930 not correctly handle a working directory with multiple
931 tags (and maybe we should prohibit such working
932 directories, but they work now and we shouldn't make
933 them stop working without more thought). */
934 if ((tag == NULL && date == NULL) && ! aflag)
936 ParseTag (&tag, &date, &nonbranch);
937 if (tag != NULL || date != NULL)
938 tag_update_dir = xstrdup (update_dir);
941 make_directory (dir);
942 Create_Admin (dir, update_dir, repository, tag, date,
943 /* This is a guess. We will rewrite it later
950 Subdir_Register (entries, (char *) NULL, dir);
953 /* Do we need to check noexec here? */
958 /* The directory exists. Check to see if it has a CVS
961 cvsadmdir = xmalloc (strlen (dir) + 80);
962 strcpy (cvsadmdir, dir);
963 strcat (cvsadmdir, "/");
964 strcat (cvsadmdir, CVSADM);
966 if (!isdir (cvsadmdir))
968 /* We cannot successfully recurse into a directory without a CVS
969 subdirectory. Generally we will have already printed
978 * If we are building dirs and not going to stdout, we make sure there is
979 * no static entries file and write the tag file as appropriate
983 if (update_build_dirs)
987 tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10);
988 (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
989 if (unlink_file (tmp) < 0 && ! existence_error (errno))
990 error (1, errno, "cannot remove file %s", tmp);
991 #ifdef SERVER_SUPPORT
993 server_clear_entstat (update_dir, repository);
998 /* keep the CVS/Tag file current with the specified arguments */
999 if (aflag || tag || date)
1001 WriteTag (dir, tag, date, 0, update_dir, repository);
1006 /* keep the CVS/Template file current */
1009 WriteTemplate (dir, update_dir);
1012 /* initialize the ignore list for this directory */
1013 ignlist = getlist ();
1016 /* print the warm fuzzy message */
1018 error (0, 0, "Updating %s", update_dir);
1026 * update_dirleave_proc () is called back by the recursion code upon leaving
1027 * a directory. It will prune empty directories if needed and will execute
1028 * any appropriate update programs.
1032 update_dirleave_proc (callerdat, dir, err, update_dir, entries)
1036 const char *update_dir;
1039 /* Delete the ignore list if it hasn't already been done. */
1043 /* If we set the tag or date for a new subdirectory in
1044 update_dirent_proc, and we're now done with that subdirectory,
1045 undo the tag/date setting. Note that we know that the tag and
1046 date were both originally NULL in this case. */
1047 if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
1060 free (tag_update_dir);
1061 tag_update_dir = NULL;
1064 if (strchr (dir, '/') == NULL)
1066 /* FIXME: chdir ("..") loses with symlinks. */
1067 /* Prune empty dirs on the way out - if necessary */
1068 (void) CVS_CHDIR ("..");
1069 if (update_prune_dirs && isemptydir (dir, 0))
1071 /* I'm not sure the existence_error is actually possible (except
1072 in cases where we really should print a message), but since
1073 this code used to ignore all errors, I'll play it safe. */
1074 if (unlink_file_dir (dir) < 0 && !existence_error (errno))
1075 error (0, errno, "cannot remove %s directory", dir);
1076 Subdir_Deregister (entries, (char *) NULL, dir);
1085 static int isremoved PROTO ((Node *, void *));
1087 /* Returns 1 if the file indicated by node has been removed. */
1089 isremoved (node, closure)
1093 Entnode *entdata = node->data;
1095 /* If the first character of the version is a '-', the file has been
1097 return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
1102 /* Returns 1 if the argument directory is completely empty, other than the
1103 existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
1104 and the directory doesn't exist, then just return 0. */
1106 isemptydir (dir, might_not_exist)
1108 int might_not_exist;
1113 if ((dirp = CVS_OPENDIR (dir)) == NULL)
1115 if (might_not_exist && existence_error (errno))
1117 error (0, errno, "cannot open directory %s for empty check", dir);
1121 while ((dp = CVS_READDIR (dirp)) != NULL)
1123 if (strcmp (dp->d_name, ".") != 0
1124 && strcmp (dp->d_name, "..") != 0)
1126 if (strcmp (dp->d_name, CVSADM) != 0)
1128 /* An entry other than the CVS directory. The directory
1129 is certainly not empty. */
1130 (void) CVS_CLOSEDIR (dirp);
1135 /* The CVS directory entry. We don't have to worry about
1136 this unless the Entries file indicates that files have
1137 been removed, but not committed, in this directory.
1138 (Removing the directory would prevent people from
1139 comitting the fact that they removed the files!) */
1142 struct saved_cwd cwd;
1144 if (save_cwd (&cwd))
1147 if (CVS_CHDIR (dir) < 0)
1148 error (1, errno, "cannot change directory to %s", dir);
1149 l = Entries_Open (0, NULL);
1150 files_removed = walklist (l, isremoved, 0);
1153 if (restore_cwd (&cwd, NULL))
1157 if (files_removed != 0)
1159 /* There are files that have been removed, but not
1160 committed! Do not consider the directory empty. */
1161 (void) CVS_CLOSEDIR (dirp);
1170 error (0, errno, "cannot read directory %s", dir);
1171 (void) CVS_CLOSEDIR (dirp);
1174 (void) CVS_CLOSEDIR (dirp);
1181 * scratch the Entries file entry associated with a file
1184 scratch_file (finfo, vers)
1185 struct file_info *finfo;
1188 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
1189 Scratch_Entry (finfo->entries, finfo->file);
1190 #ifdef SERVER_SUPPORT
1193 if (vers->ts_user == NULL)
1194 server_scratch_entry_only ();
1195 server_updated (finfo, vers,
1196 SERVER_UPDATED, (mode_t) -1,
1197 (unsigned char *) NULL,
1198 (struct buffer *) NULL);
1201 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1202 error (0, errno, "unable to remove %s", finfo->fullname);
1203 else if (!server_active)
1205 /* skip this step when the server is running since
1206 * server_updated should have handled it */
1207 /* keep the vers structure up to date in case we do a join
1208 * - if there isn't a file, it can't very well have a version number, can it?
1210 if (vers->vn_user != NULL)
1212 free (vers->vn_user);
1213 vers->vn_user = NULL;
1215 if (vers->ts_user != NULL)
1217 free (vers->ts_user);
1218 vers->ts_user = NULL;
1230 checkout_file (finfo, vers_ts, adding, merging, update_server)
1231 struct file_info *finfo;
1238 int set_time, retval = 0;
1241 struct buffer *revbuf;
1246 /* Don't screw with backup files if we're going to stdout, or if
1247 we are the server. */
1248 if (!pipeout && !server_active)
1250 backup = xmalloc (strlen (finfo->file)
1252 + sizeof (CVSPREFIX)
1254 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1255 if (isfile (finfo->file))
1256 rename_file (finfo->file, backup);
1259 /* If -f/-t wrappers are being used to wrap up a directory,
1260 then backup might be a directory instead of just a file. */
1261 if (unlink_file_dir (backup) < 0)
1263 /* Not sure if the existence_error check is needed here. */
1264 if (!existence_error (errno))
1265 /* FIXME: should include update_dir in message. */
1266 error (0, errno, "error removing %s", backup);
1273 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
1278 * if we are checking out to stdout, print a nice message to
1279 * stderr, and add the -p flag to the command */
1285 ===================================================================\n\
1287 cvs_outerr (finfo->fullname, 0);
1290 cvs_outerr (vers_ts->srcfile->path, 0);
1293 cvs_outerr (vers_ts->vn_rcs, 0);
1294 cvs_outerr ("\n***************\n", 0);
1298 #ifdef SERVER_SUPPORT
1302 && ! file_gzip_level
1304 && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
1306 revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL);
1307 status = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1308 vers_ts->vn_rcs, vers_ts->tag,
1309 vers_ts->options, RUN_TTY,
1310 checkout_to_buffer, revbuf);
1314 status = RCS_checkout (vers_ts->srcfile,
1315 pipeout ? NULL : finfo->file,
1316 vers_ts->vn_rcs, vers_ts->tag,
1317 vers_ts->options, RUN_TTY,
1318 (RCSCHECKOUTPROC) NULL, (void *) NULL);
1320 if (file_is_dead || status == 0)
1330 if (revbuf != NULL && !noexec)
1334 /* FIXME: We should have RCS_checkout return the mode.
1335 That would also fix the kludge with noexec, above, which
1336 is here only because noexec doesn't write srcfile->path
1338 if (stat (vers_ts->srcfile->path, &sb) < 0)
1340 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
1342 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
1343 error (1, errno, "cannot stat %s",
1344 vers_ts->srcfile->path);
1346 mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
1351 && !fileattr_get (finfo->file, "_watched"))
1354 xchmod (finfo->file, 1);
1357 /* We know that we are the server here, so
1358 although xchmod checks umask, we don't bother. */
1359 mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
1360 | ((mode & S_IRGRP) ? S_IWGRP : 0)
1361 | ((mode & S_IROTH) ? S_IWOTH : 0));
1366 /* A newly checked out file is never under the spell
1367 of "cvs edit". If we think we were editing it
1368 from a previous life, clean up. Would be better to
1369 check for same the working directory instead of
1370 same user, but that is hairy. */
1372 struct addremove_args args;
1374 editor_set (finfo->file, getcaller (), NULL);
1376 memset (&args, 0, sizeof args);
1377 args.remove_temp = 1;
1378 watch_modify_watchers (finfo->file, &args);
1381 /* set the time from the RCS file iff it was unknown before */
1384 && (vers_ts->vn_user == NULL ||
1385 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
1388 wrap_fromcvs_process_file (finfo->file);
1390 xvers_ts = Version_TS (finfo, options, tag, date,
1391 force_tag_match, set_time);
1392 if (strcmp (xvers_ts->options, "-V4") == 0)
1393 xvers_ts->options[0] = '\0';
1397 /* If we stored the file data into a buffer, then we
1398 didn't create a file at all, so xvers_ts->ts_user
1399 is wrong. The correct value is to have it be the
1400 same as xvers_ts->ts_rcs, meaning that the working
1401 file is unchanged from the RCS file.
1403 FIXME: We should tell Version_TS not to waste time
1404 statting the nonexistent file.
1406 FIXME: Actually, I don't think the ts_user value
1407 matters at all here. The only use I know of is
1408 that it is printed in a trace message by
1411 if (xvers_ts->ts_user != NULL)
1412 free (xvers_ts->ts_user);
1413 xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
1416 (void) time (&last_register_time);
1420 if (xvers_ts->vn_user != NULL)
1423 "warning: %s is not (any longer) pertinent",
1426 Scratch_Entry (finfo->entries, finfo->file);
1427 #ifdef SERVER_SUPPORT
1428 if (server_active && xvers_ts->ts_user == NULL)
1429 server_scratch_entry_only ();
1431 /* FIXME: Rather than always unlink'ing, and ignoring the
1432 existence_error, we should do the unlink only if
1433 vers_ts->ts_user is non-NULL. Then there would be no
1434 need to ignore an existence_error (for example, if the
1435 user removes the file while we are running). */
1436 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1438 error (0, errno, "cannot remove %s", finfo->fullname);
1442 Register (finfo->entries, finfo->file,
1443 adding ? "0" : xvers_ts->vn_rcs,
1444 xvers_ts->ts_user, xvers_ts->options,
1445 xvers_ts->tag, xvers_ts->date,
1446 (char *)0); /* Clear conflict flag on fresh checkout */
1448 /* fix up the vers structure, in case it is used by join */
1451 /* FIXME: It seems like we should be preserving ts_user
1452 * & ts_rcs here, but setting them causes problems in
1455 if (vers_ts->vn_user != NULL)
1456 free (vers_ts->vn_user);
1457 if (vers_ts->vn_rcs != NULL)
1458 free (vers_ts->vn_rcs);
1459 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1460 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1463 /* If this is really Update and not Checkout, recode history */
1464 if (strcmp (cvs_cmd_name, "update") == 0)
1465 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1468 freevers_ts (&xvers_ts);
1470 if (!really_quiet && !file_is_dead)
1472 write_letter (finfo, 'U');
1476 #ifdef SERVER_SUPPORT
1477 if (update_server && server_active)
1478 server_updated (finfo, vers_ts,
1479 merging ? SERVER_MERGED : SERVER_UPDATED,
1480 mode, (unsigned char *) NULL, revbuf);
1487 rename_file (backup, finfo->file);
1492 error (0, 0, "could not check out %s", finfo->fullname);
1499 /* If -f/-t wrappers are being used to wrap up a directory,
1500 then backup might be a directory instead of just a file. */
1501 if (unlink_file_dir (backup) < 0)
1503 /* Not sure if the existence_error check is needed here. */
1504 if (!existence_error (errno))
1505 /* FIXME: should include update_dir in message. */
1506 error (0, errno, "error removing %s", backup);
1511 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
1514 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
1520 #ifdef SERVER_SUPPORT
1522 /* This function is used to write data from a file being checked out
1526 checkout_to_buffer (callerdat, data, len)
1531 struct buffer *buf = (struct buffer *) callerdat;
1533 buf_output (buf, data, len);
1536 #endif /* SERVER_SUPPORT */
1538 #ifdef SERVER_SUPPORT
1540 /* This structure is used to pass information between patch_file and
1541 patch_file_write. */
1543 struct patch_file_data
1545 /* File name, for error messages. */
1546 const char *filename;
1547 /* File to which to write. */
1549 /* Whether to compute the MD5 checksum. */
1550 int compute_checksum;
1551 /* Data structure for computing the MD5 checksum. */
1552 struct cvs_MD5Context context;
1553 /* Set if the file has a final newline. */
1557 /* Patch a file. Runs diff. This is only done when running as the
1558 * server. The hope is that the diff will be smaller than the file
1562 patch_file (finfo, vers_ts, docheckout, file_info, checksum)
1563 struct file_info *finfo;
1566 struct stat *file_info;
1567 unsigned char *checksum;
1576 struct patch_file_data data;
1580 if (noexec || pipeout || joining ())
1586 /* If this file has been marked as being binary, then never send a
1588 if (strcmp (vers_ts->options, "-kb") == 0)
1594 /* First check that the first revision exists. If it has been nuked
1595 by cvs admin -o, then just fall back to checking out entire
1596 revisions. In some sense maybe we don't have to do this; after
1597 all cvs.texinfo says "Make sure that no-one has checked out a
1598 copy of the revision you outdate" but then again, that advice
1599 doesn't really make complete sense, because "cvs admin" operates
1600 on a working directory and so _someone_ will almost always have
1601 _some_ revision checked out. */
1605 rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
1615 /* If the revision is dead, let checkout_file handle it rather
1616 than duplicating the processing here. */
1617 if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
1623 backup = xmalloc (strlen (finfo->file)
1625 + sizeof (CVSPREFIX)
1627 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1628 if (isfile (finfo->file))
1629 rename_file (finfo->file, backup);
1632 if (unlink_file (backup) < 0
1633 && !existence_error (errno))
1634 error (0, errno, "cannot remove %s", backup);
1637 file1 = xmalloc (strlen (finfo->file)
1639 + sizeof (CVSPREFIX)
1641 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1642 file2 = xmalloc (strlen (finfo->file)
1644 + sizeof (CVSPREFIX)
1646 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1650 /* We need to check out both revisions first, to see if either one
1651 has a trailing newline. Because of this, we don't use rcsdiff,
1652 but just use diff. */
1654 e = CVS_FOPEN (file1, "w");
1656 error (1, errno, "cannot open %s", file1);
1658 data.filename = file1;
1661 data.compute_checksum = 0;
1663 /* Duplicating the client working file, so use the original sticky options.
1665 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1666 vers_ts->vn_user, vers_ts->entdata->tag,
1667 vers_ts->entdata->options, RUN_TTY,
1668 patch_file_write, (void *) &data);
1671 error (1, errno, "cannot close %s", file1);
1673 if (retcode != 0 || ! data.final_nl)
1678 e = CVS_FOPEN (file2, "w");
1680 error (1, errno, "cannot open %s", file2);
1682 data.filename = file2;
1685 data.compute_checksum = 1;
1686 cvs_MD5Init (&data.context);
1688 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
1689 vers_ts->vn_rcs, vers_ts->tag,
1690 vers_ts->options, RUN_TTY,
1691 patch_file_write, (void *) &data);
1694 error (1, errno, "cannot close %s", file2);
1696 if (retcode != 0 || ! data.final_nl)
1699 cvs_MD5Final (checksum, &data.context);
1706 size_t darg_allocated = 0;
1707 char **dargv = NULL;
1709 /* If the client does not support the Rcs-diff command, we
1710 send a context diff, and the client must invoke patch.
1711 That approach was problematical for various reasons. The
1712 new approach only requires running diff in the server; the
1713 client can handle everything without invoking an external
1715 if (!rcs_diff_patches)
1716 /* We use -c, not -u, because that is what CVS has
1717 traditionally used. Kind of a moot point, now that
1718 Rcs-diff is preferred, so there is no point in making
1719 the compatibility issues worse. */
1720 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c");
1722 /* Now that diff is librarified, we could be passing -a if
1723 we wanted to. However, it is unclear to me whether we
1724 would want to. Does diff -a, in any significant
1725 percentage of cases, produce patches which are smaller
1726 than the files it is patching? I guess maybe text
1727 files with character sets which diff regards as
1728 'binary'. Conversely, do they tend to be much larger
1729 in the bad cases? This needs some more
1730 thought/investigation, I suspect. */
1731 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
1732 retcode = diff_exec (file1, file2, NULL, NULL, dargc, dargv,
1734 run_arg_free_p (dargc, dargv);
1737 /* A retcode of 0 means no differences. 1 means some differences. */
1747 struct stat file2_info;
1749 /* Check to make sure the patch is really shorter */
1750 if (CVS_STAT (file2, &file2_info) < 0)
1751 error (1, errno, "could not stat %s", file2);
1752 if (CVS_STAT (finfo->file, file_info) < 0)
1753 error (1, errno, "could not stat %s", finfo->file);
1754 if (file2_info.st_size <= file_info->st_size)
1760 # define BINARY "Binary"
1761 char buf[sizeof BINARY];
1764 /* Check the diff output to make sure patch will be handle it. */
1765 e = CVS_FOPEN (finfo->file, "r");
1767 error (1, errno, "could not open diff output file %s",
1769 c = fread (buf, 1, sizeof BINARY - 1, e);
1771 if (strcmp (buf, BINARY) == 0)
1773 /* These are binary files. We could use diff -a, but
1774 patch can't handle that. */
1784 /* Stat the original RCS file, and then adjust it the way
1785 that RCS_checkout would. FIXME: This is an abstraction
1787 if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0)
1788 error (1, errno, "could not stat %s", vers_ts->srcfile->path);
1789 if (chmod (finfo->file,
1790 file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
1792 error (0, errno, "cannot change mode of file %s", finfo->file);
1794 && !fileattr_get (finfo->file, "_watched"))
1795 xchmod (finfo->file, 1);
1797 /* This stuff is just copied blindly from checkout_file. I
1798 don't really know what it does. */
1799 xvers_ts = Version_TS (finfo, options, tag, date,
1800 force_tag_match, 0);
1801 if (strcmp (xvers_ts->options, "-V4") == 0)
1802 xvers_ts->options[0] = '\0';
1804 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1805 xvers_ts->ts_user, xvers_ts->options,
1806 xvers_ts->tag, xvers_ts->date, NULL);
1808 if (CVS_STAT (finfo->file, file_info) < 0)
1809 error (1, errno, "could not stat %s", finfo->file);
1811 /* If this is really Update and not Checkout, record history. */
1812 if (strcmp (cvs_cmd_name, "update") == 0)
1813 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
1814 finfo->file, finfo->repository);
1816 freevers_ts (&xvers_ts);
1820 write_letter (finfo, 'P');
1825 int old_errno = errno; /* save errno value over the rename */
1827 if (isfile (backup))
1828 rename_file (backup, finfo->file);
1830 if (retcode != 0 && retcode != 1)
1831 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1832 "could not diff %s", finfo->fullname);
1838 if (unlink_file (backup) < 0
1839 && !existence_error (errno))
1840 error (0, errno, "cannot remove %s", backup);
1841 if (unlink_file (file1) < 0
1842 && !existence_error (errno))
1843 error (0, errno, "cannot remove %s", file1);
1844 if (unlink_file (file2) < 0
1845 && !existence_error (errno))
1846 error (0, errno, "cannot remove %s", file2);
1856 /* Write data to a file. Record whether the last byte written was a
1857 newline. Optionally compute a checksum. This is called by
1858 patch_file via RCS_checkout. */
1861 patch_file_write (callerdat, buffer, len)
1866 struct patch_file_data *data = (struct patch_file_data *) callerdat;
1868 if (fwrite (buffer, 1, len, data->fp) != len)
1869 error (1, errno, "cannot write %s", data->filename);
1871 data->final_nl = (buffer[len - 1] == '\n');
1873 if (data->compute_checksum)
1874 cvs_MD5Update (&data->context, (unsigned char *) buffer, len);
1877 #endif /* SERVER_SUPPORT */
1880 * Several of the types we process only print a bit of information consisting
1881 * of a single letter and the name.
1884 write_letter (finfo, letter)
1885 struct file_info *finfo;
1891 /* Big enough for "+updated" or any of its ilk. */
1900 /* We don't yet support tagged output except for "U". */
1906 sprintf (buf, "+%s", tag);
1907 cvs_output_tagged (buf, NULL);
1912 cvs_output_tagged ("text", buf);
1913 cvs_output_tagged ("fname", finfo->fullname);
1914 cvs_output_tagged ("newline", NULL);
1917 sprintf (buf, "-%s", tag);
1918 cvs_output_tagged (buf, NULL);
1926 /* Reregister a file after a merge. */
1928 RegisterMerge PROTO((struct file_info *finfo, Vers_TS *vers,
1929 const char *backup, int has_conflicts));
1931 RegisterMerge (finfo, vers, backup, has_conflicts)
1932 struct file_info *finfo;
1937 /* This file is the result of a merge, which means that it has
1938 been modified. We use a special timestamp string which will
1939 not compare equal to any actual timestamp. */
1944 time (&last_register_time);
1945 cp = time_stamp (finfo->file);
1947 Register (finfo->entries, finfo->file, vers->vn_rcs ? vers->vn_rcs : "0",
1948 "Result of merge", vers->options, vers->tag, vers->date, cp);
1952 #ifdef SERVER_SUPPORT
1953 /* Send the new contents of the file before the message. If we
1954 wanted to be totally correct, we would have the client write
1955 the message only after the file has safely been written. */
1958 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
1960 server_updated (finfo, vers, SERVER_MERGED, (mode_t) -1, NULL, NULL);
1968 * Do all the magic associated with a file which needs to be merged
1971 merge_file (finfo, vers)
1972 struct file_info *finfo;
1980 assert (vers->vn_user);
1983 * The users currently modified file is moved to a backup file name
1984 * ".#filename.version", so that it will stay around for a few days
1985 * before being automatically removed by some cron daemon. The "version"
1986 * is the version of the file that the user was most up-to-date with
1989 backup = xmalloc (strlen (finfo->file)
1990 + strlen (vers->vn_user)
1991 + sizeof (BAKPREFIX)
1993 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1995 if (unlink_file (backup) && !existence_error (errno))
1996 error (0, errno, "unable to remove %s", backup);
1997 copy_file (finfo->file, backup);
1998 xchmod (finfo->file, 1);
2000 if (strcmp (vers->options, "-kb") == 0
2001 || wrap_merge_is_copy (finfo->file)
2002 || special_file_mismatch (finfo, NULL, vers->vn_rcs))
2004 /* For binary files, a merge is always a conflict. Same for
2005 files whose permissions or linkage do not match. We give the
2006 user the two files, and let them resolve it. It is possible
2007 that we should require a "touch foo" or similar step before
2008 we allow a checkin. */
2010 /* TODO: it may not always be necessary to regard a permission
2011 mismatch as a conflict. The working file and the RCS file
2012 have a common ancestor `A'; if the working file's permissions
2013 match A's, then it's probably safe to overwrite them with the
2014 RCS permissions. Only if the working file, the RCS file, and
2015 A all disagree should this be considered a conflict. But more
2016 thought needs to go into this, and in the meantime it is safe
2017 to treat any such mismatch as an automatic conflict. -twp */
2019 retcode = RCS_checkout (finfo->rcs, finfo->file,
2020 vers->vn_rcs, vers->tag,
2021 vers->options, NULL, NULL, NULL);
2024 error (0, 0, "failed to check out `%s' file", finfo->fullname);
2025 error (0, 0, "restoring `%s' from backup file `%s'",
2026 finfo->fullname, backup);
2027 rename_file (backup, finfo->file);
2031 xchmod (finfo->file, 1);
2033 RegisterMerge (finfo, vers, backup, 1);
2035 /* Is there a better term than "nonmergeable file"? What we
2036 really mean is, not something that CVS cannot or does not
2037 want to merge (there might be an external manual or
2038 automatic merge process). */
2039 error (0, 0, "nonmergeable file needs merge");
2040 error (0, 0, "revision %s from repository is now in %s",
2041 vers->vn_rcs, finfo->fullname);
2042 error (0, 0, "file from working directory is now in %s", backup);
2043 write_letter (finfo, 'C');
2045 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2051 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2052 vers->options, vers->vn_user, vers->vn_rcs);
2053 if (status != 0 && status != 1)
2055 error (0, status == -1 ? errno : 0,
2056 "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
2057 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2058 finfo->fullname, backup);
2059 rename_file (backup, finfo->file);
2064 if (strcmp (vers->options, "-V4") == 0)
2065 vers->options[0] = '\0';
2067 /* fix up the vers structure, in case it is used by join */
2070 /* FIXME: Throwing away the original revision info is almost
2071 certainly wrong -- what if join_rev1 is "BASE"? */
2072 if (vers->vn_user != NULL)
2073 free (vers->vn_user);
2074 vers->vn_user = xstrdup (vers->vn_rcs);
2077 RegisterMerge (finfo, vers, backup, status);
2079 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2080 xcmp on the temporary files without much hassle, I think. */
2081 if (!noexec && !xcmp (backup, finfo->file))
2083 cvs_output (finfo->fullname, 0);
2084 cvs_output (" already contains the differences between ", 0);
2085 cvs_output (vers->vn_user, 0);
2086 cvs_output (" and ", 0);
2087 cvs_output (vers->vn_rcs, 0);
2088 cvs_output ("\n", 1);
2090 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2098 error (0, 0, "conflicts found in %s", finfo->fullname);
2100 write_letter (finfo, 'C');
2102 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2106 else if (retcode == -1)
2108 error (1, errno, "fork failed while examining update of %s",
2113 write_letter (finfo, 'M');
2114 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2126 * Do all the magic associated with a file which needs to be joined
2127 * (reached via the -j option to checkout or update).
2130 * finfo File information about the destination file.
2131 * vers The Vers_TS structure for finfo.
2134 * join_rev1 From the command line.
2135 * join_rev2 From the command line.
2136 * server_active Natch.
2139 * 1. Is not called in client mode.
2142 join_file (finfo, vers)
2143 struct file_info *finfo;
2158 fprintf (stderr, "%s-> join_file(%s, %s%s%s%s, %s, %s)\n",
2161 vers->tag ? vers->tag : "",
2162 vers->tag ? " (" : "",
2163 vers->vn_rcs ? vers->vn_rcs : "",
2164 vers->tag ? ")" : "",
2165 join_rev1 ? join_rev1 : "",
2166 join_rev2 ? join_rev2 : "");
2173 /* Determine if we need to do anything at all. */
2174 if (vers->srcfile == NULL ||
2175 vers->srcfile->path == NULL)
2180 /* If only one join revision is specified, it becomes the second
2190 /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
2191 below about vn_user. */
2193 /* Convert the second revision, walking branches and dates. */
2194 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
2196 /* If this is a merge of two revisions, get the first revision.
2197 If only one join tag was specified, then the first revision is
2198 the greatest common ancestor of the second revision and the
2201 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL);
2204 /* Note that we use vn_rcs here, since vn_user may contain a
2205 special string such as "-nn". */
2206 if (vers->vn_rcs == NULL)
2208 else if (rev2 == NULL)
2210 /* This means that the file never existed on the branch.
2211 It does not mean that the file was removed on the
2212 branch: that case is represented by a dead rev2. If
2213 the file never existed on the branch, then we have
2214 nothing to merge, so we just return. */
2218 rev1 = gca (vers->vn_rcs, rev2);
2221 /* Handle a nonexistent or dead merge target. */
2222 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
2230 /* If the first revision doesn't exist either, then there is
2231 no change between the two revisions, so we don't do
2233 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2240 /* If we are merging two revisions, then the file was removed
2241 between the first revision and the second one. In this
2242 case we want to mark the file for removal.
2244 If we are merging one revision, then the file has been
2245 removed between the greatest common ancestor and the merge
2246 revision. From the perspective of the branch on to which
2247 we ar emerging, which may be the trunk, either 1) the file
2248 does not currently exist on the target, or 2) the file has
2249 not been modified on the target branch since the greatest
2250 common ancestor, or 3) the file has been modified on the
2251 target branch since the greatest common ancestor. In case
2252 1 there is nothing to do. In case 2 we mark the file for
2253 removal. In case 3 we have a conflict.
2255 Note that the handling is slightly different depending upon
2256 whether one or two join targets were specified. If two
2257 join targets were specified, we don't check whether the
2258 file was modified since a given point. My reasoning is
2259 that if you ask for an explicit merge between two tags,
2260 then you want to merge in whatever was changed between
2261 those two tags. If a file was removed between the two
2262 tags, then you want it to be removed. However, if you ask
2263 for a merge of a branch, then you want to merge in all
2264 changes which were made on the branch. If a file was
2265 removed on the branch, that is a change to the file. If
2266 the file was also changed on the main line, then that is
2267 also a change. These two changes--the file removal and the
2268 modification--must be merged. This is a conflict. */
2270 /* If the user file is dead, or does not exist, or has been
2271 marked for removal, then there is nothing to do. */
2272 if (vers->vn_user == NULL
2273 || vers->vn_user[0] == '-'
2274 || RCS_isdead (vers->srcfile, vers->vn_user))
2280 /* If the user file has been marked for addition, or has been
2281 locally modified, then we have a conflict which we can not
2282 resolve. No_Difference will already have been called in
2283 this case, so comparing the timestamps is sufficient to
2284 determine whether the file is locally modified. */
2285 if (/* may have changed on destination branch */
2286 /* file added locally */
2287 !strcmp (vers->vn_user, "0")
2288 || /* destination branch modified in repository */
2289 strcmp (rev1, vers->vn_user)
2290 || /* locally modified */
2291 vers->ts_user && strcmp (vers->ts_user, vers->ts_rcs))
2293 /* The removal should happen if either the file has never changed
2294 * on the destination or the file has changed to be identical to
2295 * the first join revision.
2297 * ------R-----------D
2299 * \----J1---J2-----S
2305 * R is source branch root/GCA.
2306 * if J1 == D removal should happen
2307 * if D == R removal should happen
2310 * (In the source, J2 = REV2, D = user file (potentially VN_USER),
2311 * R = GCA computed below)
2313 char *gca_rev1 = gca (rev1, vers->vn_user);
2314 #ifdef SERVER_SUPPORT
2315 if (server_active && !isreadable (finfo->file))
2318 /* The file is up to date. Need to check out the current
2321 /* FIXME - see the FIXME comment above the call to RCS_checkout
2322 * in the patch_file function.
2324 retcode = RCS_checkout (vers->srcfile, finfo->file,
2325 vers->vn_user, vers->tag,
2326 NULL, RUN_TTY, NULL, NULL);
2329 "failed to check out %s file", finfo->fullname);
2332 if (/* genuinely changed on destination branch */
2333 RCS_cmp_file (vers->srcfile, gca_rev1, NULL,
2334 NULL, vers->options, finfo->file)
2335 && /* genuinely different from REV1 */
2336 RCS_cmp_file (vers->srcfile, rev1, NULL,
2337 NULL, vers->options, finfo->file))
2349 "file %s has been removed in revision %s as of %s, but the destination is incompatibly modified",
2350 finfo->fullname, jrev2, jdate2);
2353 "file %s has been removed in revision %s, but the destination is incompatibly modified",
2354 finfo->fullname, jrev2);
2356 /* Register the conflict with the client. */
2358 /* FIXME: vers->ts_user should always be set here but sometimes
2359 * isn't, namely when checkout_file() has just created the file,
2360 * but simply setting it in checkout_file() appears to cause other
2363 if (isfile (finfo->file))
2364 cp = time_stamp (finfo->file);
2366 cp = xstrdup (vers->ts_user);
2368 Register (finfo->entries, finfo->file, vers->vn_user,
2369 "Result of merge", vers->options, vers->tag, vers->date,
2371 write_letter (finfo, 'C');
2374 #ifdef SERVER_SUPPORT
2375 /* Abuse server_checked_in() to send the updated entry without
2376 * needing to update the file.
2379 server_checked_in (finfo->file, finfo->update_dir,
2386 /* The user file exists and has not been modified. Mark it
2387 for removal. FIXME: If we are doing a checkout, this has
2388 the effect of first checking out the file, and then
2389 removing it. It would be better to just register the
2392 The same goes for a removal then an add. e.g.
2393 cvs up -rbr -jbr2 could remove and readd the same file
2395 /* save the rev since server_updated might invalidate it */
2396 mrev = xmalloc (strlen (vers->vn_user) + 2);
2397 sprintf (mrev, "-%s", vers->vn_user);
2398 #ifdef SERVER_SUPPORT
2401 server_scratch (finfo->file);
2402 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
2403 (unsigned char *) NULL, (struct buffer *) NULL);
2406 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
2407 vers->options, vers->tag, vers->date, vers->ts_conflict);
2409 /* We need to check existence_error here because if we are
2410 running as the server, and the file is up to date in the
2411 working directory, the client will not have sent us a copy. */
2412 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
2413 error (0, errno, "cannot remove file %s", finfo->fullname);
2414 #ifdef SERVER_SUPPORT
2416 server_checked_in (finfo->file, finfo->update_dir,
2420 error (0, 0, "scheduling %s for removal", finfo->fullname);
2425 /* If the two merge revisions are the same, then there is nothing
2426 * to do. This needs to be checked before the rev2 == up-to-date base
2427 * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
2428 * "already contains the changes between <rev1> and <rev1>" message.
2430 if (rev1 && strcmp (rev1, rev2) == 0)
2437 /* If we know that the user file is up-to-date, then it becomes an
2438 * optimization to skip the merge when rev2 is the same as the base
2439 * revision. i.e. we know that diff3(file2,file1,file2) will produce
2442 if (vers->vn_user != NULL && vers->ts_user != NULL
2443 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2444 && strcmp (rev2, vers->vn_user) == 0)
2448 cvs_output (finfo->fullname, 0);
2449 cvs_output (" already contains the differences between ", 0);
2450 cvs_output (rev1 ? rev1 : "creation", 0);
2451 cvs_output (" and ", 0);
2452 cvs_output (rev2, 0);
2453 cvs_output ("\n", 1);
2463 /* If rev1 is dead or does not exist, then the file was added
2464 between rev1 and rev2. */
2465 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2471 /* If the file does not exist in the working directory, then
2472 we can just check out the new revision and mark it for
2474 if (vers->vn_user == NULL)
2476 char *saved_options = options;
2479 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
2481 /* Reset any keyword expansion option. Otherwise, when a
2482 command like `cvs update -kk -jT1 -jT2' creates a new file
2483 (because a file had the T2 tag, but not T1), the subsequent
2484 commit of that just-added file effectively would set the
2485 admin `-kk' option for that file in the repository. */
2488 /* FIXME: If checkout_file fails, we should arrange to
2489 return a non-zero exit status. */
2490 status = checkout_file (finfo, xvers, 1, 0, 1);
2491 options = saved_options;
2493 freevers_ts (&xvers);
2498 /* The file currently exists in the working directory, so we
2499 have a conflict which we can not resolve. Note that this
2500 is true even if the file is marked for addition or removal. */
2504 "file %s exists, but has been added in revision %s as of %s",
2505 finfo->fullname, jrev2, jdate2);
2508 "file %s exists, but has been added in revision %s",
2509 finfo->fullname, jrev2);
2514 /* If there is no working file, then we can't do the merge. */
2515 if (vers->vn_user == NULL || vers->vn_user[0] == '-')
2522 "file %s does not exist, but is present in revision %s as of %s",
2523 finfo->fullname, jrev2, jdate2);
2526 "file %s does not exist, but is present in revision %s",
2527 finfo->fullname, jrev2);
2529 /* FIXME: Should we arrange to return a non-zero exit status? */
2534 #ifdef SERVER_SUPPORT
2535 if (server_active && !isreadable (finfo->file))
2538 /* The file is up to date. Need to check out the current contents. */
2539 /* FIXME - see the FIXME comment above the call to RCS_checkout in the
2540 * patch_file function.
2542 retcode = RCS_checkout (vers->srcfile, finfo->file,
2543 vers->vn_user, vers->tag,
2544 (char *) NULL, RUN_TTY,
2545 (RCSCHECKOUTPROC) NULL, (void *) NULL);
2548 "failed to check out %s file", finfo->fullname);
2553 * The users currently modified file is moved to a backup file name
2554 * ".#filename.version", so that it will stay around for a few days
2555 * before being automatically removed by some cron daemon. The "version"
2556 * is the version of the file that the user was most up-to-date with
2559 backup = xmalloc (strlen (finfo->file)
2560 + strlen (vers->vn_user)
2561 + sizeof (BAKPREFIX)
2563 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
2565 if (unlink_file (backup) < 0
2566 && !existence_error (errno))
2567 error (0, errno, "cannot remove %s", backup);
2568 copy_file (finfo->file, backup);
2569 xchmod (finfo->file, 1);
2571 t_options = vers->options;
2573 if (*t_options == '\0')
2574 t_options = "-kk"; /* to ignore keyword expansions */
2577 /* If the source of the merge is the same as the working file
2578 revision, then we can just RCS_checkout the target (no merging
2579 as such). In the text file case, this is probably quite
2580 similar to the RCS_merge, but in the binary file case,
2581 RCS_merge gives all kinds of trouble. */
2582 if (vers->vn_user != NULL
2583 && strcmp (rev1, vers->vn_user) == 0
2584 /* See comments above about how No_Difference has already been
2586 && vers->ts_user != NULL
2587 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2589 /* Avoid this in the text file case. See below for why.
2591 && (strcmp (t_options, "-kb") == 0
2592 || wrap_merge_is_copy (finfo->file)))
2594 /* FIXME: Verify my comment below:
2596 * RCS_merge does nothing with keywords. It merges the changes between
2597 * two revisions without expanding the keywords (it might expand in
2598 * -kk mode before computing the diff between rev1 and rev2 - I'm not
2599 * sure). In other words, the keyword lines in the current work file
2602 * Therfore, checking out the destination revision (rev2) is probably
2603 * incorrect in the text case since we should see the keywords that were
2604 * substituted into the original file at the time it was checked out
2605 * and not the keywords from rev2.
2607 * Also, it is safe to pass in NULL for nametag since we know no
2608 * substitution is happening during the binary mode checkout.
2610 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL, t_options,
2611 RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0 )
2616 /* OK, this is really stupid. RCS_checkout carefully removes
2617 write permissions, and we carefully put them back. But
2618 until someone gets around to fixing it, that seems like the
2619 easiest way to get what would seem to be the right mode.
2620 I don't check CVSWRITE or _watched; I haven't thought about
2621 that in great detail, but it seems like a watched file should
2622 be checked out (writable) after a merge. */
2623 xchmod (finfo->file, 1);
2625 /* Traditionally, the text file case prints a whole bunch of
2626 scary looking and verbose output which fails to tell the user
2627 what is really going on (it gives them rev1 and rev2 but doesn't
2628 indicate in any way that rev1 == vn_user). I think just a
2629 simple "U foo" is good here; it seems analogous to the case in
2630 which the file was added on the branch in terms of what to
2632 write_letter (finfo, 'U');
2634 else if (strcmp (t_options, "-kb") == 0
2635 || wrap_merge_is_copy (finfo->file)
2636 || special_file_mismatch (finfo, rev1, rev2))
2638 /* We are dealing with binary files, or files with a
2639 permission/linkage mismatch (this second case only occurs when
2640 PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
2641 need to take place. This is a conflict. We give the user
2642 the two files, and let them resolve it. It is possible
2643 that we should require a "touch foo" or similar step before
2644 we allow a checkin. */
2645 if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL,
2646 t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
2651 /* OK, this is really stupid. RCS_checkout carefully removes
2652 write permissions, and we carefully put them back. But
2653 until someone gets around to fixing it, that seems like the
2654 easiest way to get what would seem to be the right mode.
2655 I don't check CVSWRITE or _watched; I haven't thought about
2656 that in great detail, but it seems like a watched file should
2657 be checked out (writable) after a merge. */
2658 xchmod (finfo->file, 1);
2660 /* Hmm. We don't give them REV1 anywhere. I guess most people
2661 probably don't have a 3-way merge tool for the file type in
2662 question, and might just get confused if we tried to either
2663 provide them with a copy of the file from REV1, or even just
2664 told them what REV1 is so they can get it themself, but it
2665 might be worth thinking about. */
2666 /* See comment in merge_file about the "nonmergeable file"
2668 error (0, 0, "nonmergeable file needs merge");
2669 error (0, 0, "revision %s from repository is now in %s",
2670 rev2, finfo->fullname);
2671 error (0, 0, "file from working directory is now in %s", backup);
2672 write_letter (finfo, 'C');
2675 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2676 t_options, rev1, rev2);
2682 error (0, status == -1 ? errno : 0,
2683 "could not merge revision %s of %s", rev2, finfo->fullname);
2684 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2685 finfo->fullname, backup);
2686 rename_file (backup, finfo->file);
2689 else /* status == 0 */
2691 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2692 xcmp on the temporary files without much hassle, I think. */
2693 if (!noexec && !xcmp (backup, finfo->file))
2697 cvs_output (finfo->fullname, 0);
2698 cvs_output (" already contains the differences between ", 0);
2699 cvs_output (rev1, 0);
2700 cvs_output (" and ", 0);
2701 cvs_output (rev2, 0);
2702 cvs_output ("\n", 1);
2705 /* and skip the registering and sending the new file since it
2706 * hasn't been updated.
2712 /* The file has changed, but if we just checked it out it may
2713 still have the same timestamp it did when it was first
2714 registered above in checkout_file. We register it again with a
2715 dummy timestamp to make sure that later runs of CVS will
2716 recognize that it has changed.
2718 We don't actually need to register again if we called
2719 RCS_checkout above, and we aren't running as the server.
2720 However, that is not the normal case, and calling Register
2721 again won't cost much in that case. */
2722 RegisterMerge (finfo, vers, backup, status);
2733 * Report whether revisions REV1 and REV2 of FINFO agree on:
2736 * . major and minor device numbers
2740 * If either REV1 or REV2 is NULL, the working copy is used instead.
2742 * Return 1 if the files differ on these data.
2746 special_file_mismatch (finfo, rev1, rev2)
2747 struct file_info *finfo;
2751 #ifdef PRESERVE_PERMISSIONS_SUPPORT
2755 uid_t rev1_uid, rev2_uid;
2756 gid_t rev1_gid, rev2_gid;
2757 mode_t rev1_mode, rev2_mode;
2758 unsigned long dev_long;
2759 dev_t rev1_dev, rev2_dev;
2760 char *rev1_symlink = NULL;
2761 char *rev2_symlink = NULL;
2762 List *rev1_hardlinks = NULL;
2763 List *rev2_hardlinks = NULL;
2764 int check_uids, check_gids, check_modes;
2767 /* If we don't care about special file info, then
2768 don't report a mismatch in any case. */
2769 if (!preserve_perms)
2772 /* When special_file_mismatch is called from No_Difference, the
2773 RCS file has been only partially parsed. We must read the
2774 delta tree in order to compare special file info recorded in
2775 the delta nodes. (I think this is safe. -twp) */
2776 if (finfo->rcs->flags & PARTIAL)
2777 RCS_reparsercsfile (finfo->rcs, NULL, NULL);
2779 check_uids = check_gids = check_modes = 1;
2781 /* Obtain file information for REV1. If this is null, then stat
2782 finfo->file and use that info. */
2783 /* If a revision does not know anything about its status,
2784 then presumably it doesn't matter, and indicates no conflict. */
2788 if (islink (finfo->file))
2789 rev1_symlink = xreadlink (finfo->file);
2792 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2793 if (CVS_LSTAT (finfo->file, &sb) < 0)
2794 error (1, errno, "could not get file information for %s",
2796 rev1_uid = sb.st_uid;
2797 rev1_gid = sb.st_gid;
2798 rev1_mode = sb.st_mode;
2799 if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
2800 rev1_dev = sb.st_rdev;
2802 error (1, 0, "cannot handle device files on this system (%s)",
2806 rev1_hardlinks = list_linked_files_on_disk (finfo->file);
2810 n = findnode (finfo->rcs->versions, rev1);
2813 n = findnode (vp->other_delta, "symlink");
2815 rev1_symlink = xstrdup (n->data);
2818 n = findnode (vp->other_delta, "owner");
2820 check_uids = 0; /* don't care */
2822 rev1_uid = strtoul (n->data, NULL, 10);
2824 n = findnode (vp->other_delta, "group");
2826 check_gids = 0; /* don't care */
2828 rev1_gid = strtoul (n->data, NULL, 10);
2830 n = findnode (vp->other_delta, "permissions");
2832 check_modes = 0; /* don't care */
2834 rev1_mode = strtoul (n->data, NULL, 8);
2836 n = findnode (vp->other_delta, "special");
2838 rev1_mode |= S_IFREG;
2841 /* If the size of `ftype' changes, fix the sscanf call also */
2843 if (sscanf (n->data, "%15s %lu", ftype,
2845 error (1, 0, "%s:%s has bad `special' newphrase %s",
2846 finfo->file, rev1, (char *)n->data);
2847 rev1_dev = dev_long;
2848 if (strcmp (ftype, "character") == 0)
2849 rev1_mode |= S_IFCHR;
2850 else if (strcmp (ftype, "block") == 0)
2851 rev1_mode |= S_IFBLK;
2853 error (0, 0, "%s:%s unknown file type `%s'",
2854 finfo->file, rev1, ftype);
2857 rev1_hardlinks = vp->hardlinks;
2858 if (rev1_hardlinks == NULL)
2859 rev1_hardlinks = getlist();
2863 /* Obtain file information for REV2. */
2866 if (islink (finfo->file))
2867 rev2_symlink = xreadlink (finfo->file);
2870 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2871 if (CVS_LSTAT (finfo->file, &sb) < 0)
2872 error (1, errno, "could not get file information for %s",
2874 rev2_uid = sb.st_uid;
2875 rev2_gid = sb.st_gid;
2876 rev2_mode = sb.st_mode;
2877 if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
2878 rev2_dev = sb.st_rdev;
2880 error (1, 0, "cannot handle device files on this system (%s)",
2884 rev2_hardlinks = list_linked_files_on_disk (finfo->file);
2888 n = findnode (finfo->rcs->versions, rev2);
2891 n = findnode (vp->other_delta, "symlink");
2893 rev2_symlink = xstrdup (n->data);
2896 n = findnode (vp->other_delta, "owner");
2898 check_uids = 0; /* don't care */
2900 rev2_uid = strtoul (n->data, NULL, 10);
2902 n = findnode (vp->other_delta, "group");
2904 check_gids = 0; /* don't care */
2906 rev2_gid = strtoul (n->data, NULL, 10);
2908 n = findnode (vp->other_delta, "permissions");
2910 check_modes = 0; /* don't care */
2912 rev2_mode = strtoul (n->data, NULL, 8);
2914 n = findnode (vp->other_delta, "special");
2916 rev2_mode |= S_IFREG;
2919 /* If the size of `ftype' changes, fix the sscanf call also */
2921 if (sscanf (n->data, "%15s %lu", ftype,
2923 error (1, 0, "%s:%s has bad `special' newphrase %s",
2924 finfo->file, rev2, (char *)n->data);
2925 rev2_dev = dev_long;
2926 if (strcmp (ftype, "character") == 0)
2927 rev2_mode |= S_IFCHR;
2928 else if (strcmp (ftype, "block") == 0)
2929 rev2_mode |= S_IFBLK;
2931 error (0, 0, "%s:%s unknown file type `%s'",
2932 finfo->file, rev2, ftype);
2935 rev2_hardlinks = vp->hardlinks;
2936 if (rev2_hardlinks == NULL)
2937 rev2_hardlinks = getlist();
2941 /* Check the user/group ownerships and file permissions, printing
2942 an error for each mismatch found. Return 0 if all characteristics
2943 matched, and 1 otherwise. */
2947 /* Compare symlinks first, since symlinks are simpler (don't have
2948 any other characteristics). */
2949 if (rev1_symlink != NULL && rev2_symlink == NULL)
2951 error (0, 0, "%s is a symbolic link",
2952 (rev1 == NULL ? "working file" : rev1));
2955 else if (rev1_symlink == NULL && rev2_symlink != NULL)
2957 error (0, 0, "%s is a symbolic link",
2958 (rev2 == NULL ? "working file" : rev2));
2961 else if (rev1_symlink != NULL)
2962 result = (strcmp (rev1_symlink, rev2_symlink) == 0);
2965 /* Compare user ownership. */
2966 if (check_uids && rev1_uid != rev2_uid)
2968 error (0, 0, "%s: owner mismatch between %s and %s",
2970 (rev1 == NULL ? "working file" : rev1),
2971 (rev2 == NULL ? "working file" : rev2));
2975 /* Compare group ownership. */
2976 if (check_gids && rev1_gid != rev2_gid)
2978 error (0, 0, "%s: group mismatch between %s and %s",
2980 (rev1 == NULL ? "working file" : rev1),
2981 (rev2 == NULL ? "working file" : rev2));
2985 /* Compare permissions. */
2987 (rev1_mode & 07777) != (rev2_mode & 07777))
2989 error (0, 0, "%s: permission mismatch between %s and %s",
2991 (rev1 == NULL ? "working file" : rev1),
2992 (rev2 == NULL ? "working file" : rev2));
2996 /* Compare device file characteristics. */
2997 if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
2999 error (0, 0, "%s: %s and %s are different file types",
3001 (rev1 == NULL ? "working file" : rev1),
3002 (rev2 == NULL ? "working file" : rev2));
3005 else if (S_ISBLK (rev1_mode))
3007 if (rev1_dev != rev2_dev)
3009 error (0, 0, "%s: device numbers of %s and %s do not match",
3011 (rev1 == NULL ? "working file" : rev1),
3012 (rev2 == NULL ? "working file" : rev2));
3017 /* Compare hard links. */
3018 if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
3020 error (0, 0, "%s: hard linkage of %s and %s do not match",
3022 (rev1 == NULL ? "working file" : rev1),
3023 (rev2 == NULL ? "working file" : rev2));
3028 if (rev1_symlink != NULL)
3029 free (rev1_symlink);
3030 if (rev2_symlink != NULL)
3031 free (rev2_symlink);
3032 if (rev1_hardlinks != NULL)
3033 dellist (&rev1_hardlinks);
3034 if (rev2_hardlinks != NULL)
3035 dellist (&rev2_hardlinks);
3048 return join_rev1 != NULL;