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