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