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