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