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