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 1.4 kit. 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 #ifdef SERVER_SUPPORT 38 #include "md5.h" 39 #endif 40 #include "watch.h" 41 #include "fileattr.h" 42 #include "edit.h" 43 44 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts, 45 int adding)); 46 #ifdef SERVER_SUPPORT 47 static int patch_file PROTO ((struct file_info *finfo, 48 Vers_TS *vers_ts, 49 int *docheckout, struct stat *file_info, 50 unsigned char *checksum)); 51 #endif 52 static int isemptydir PROTO((char *dir)); 53 static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers)); 54 static int scratch_file PROTO((struct file_info *finfo)); 55 static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir, 56 char *repository, char *update_dir, 57 List *entries)); 58 static int update_dirleave_proc PROTO ((void *callerdat, char *dir, 59 int err, char *update_dir, 60 List *entries)); 61 static int update_fileproc PROTO ((void *callerdat, struct file_info *)); 62 static int update_filesdone_proc PROTO ((void *callerdat, int err, 63 char *repository, char *update_dir, 64 List *entries)); 65 static int write_letter PROTO((char *file, int letter, char *update_dir)); 66 #ifdef SERVER_SUPPORT 67 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts)); 68 #else 69 static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts)); 70 #endif 71 72 static char *options = NULL; 73 static char *tag = NULL; 74 static char *date = NULL; 75 static char *join_rev1, *date_rev1; 76 static char *join_rev2, *date_rev2; 77 static int aflag = 0; 78 static int force_tag_match = 1; 79 static int update_build_dirs = 0; 80 static int update_prune_dirs = 0; 81 static int pipeout = 0; 82 #ifdef SERVER_SUPPORT 83 static int patches = 0; 84 #endif 85 static List *ignlist = (List *) NULL; 86 static time_t last_register_time; 87 static const char *const update_usage[] = 88 { 89 "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n", 90 " [-I ign] [-W spec] [files...]\n", 91 "\t-A\tReset any sticky tags/date/kopts.\n", 92 "\t-P\tPrune empty directories.\n", 93 "\t-d\tBuild directories, like checkout does.\n", 94 "\t-f\tForce a head revision match if tag/date not found.\n", 95 "\t-l\tLocal directory only, no recursion.\n", 96 "\t-R\tProcess directories recursively.\n", 97 "\t-p\tSend updates to standard output (avoids stickiness).\n", 98 "\t-k kopt\tUse RCS kopt -k option on checkout.\n", 99 "\t-r rev\tUpdate using specified revision/tag (is sticky).\n", 100 "\t-D date\tSet date to update from (is sticky).\n", 101 "\t-j rev\tMerge in changes made between current revision and rev.\n", 102 "\t-I ign\tMore files to ignore (! to reset).\n", 103 "\t-W spec\tWrappers specification line.\n", 104 NULL 105 }; 106 107 /* 108 * update is the argv,argc based front end for arg parsing 109 */ 110 int 111 update (argc, argv) 112 int argc; 113 char **argv; 114 { 115 int c, err; 116 int local = 0; /* recursive by default */ 117 int which; /* where to look for files and dirs */ 118 119 if (argc == -1) 120 usage (update_usage); 121 122 ign_setup (); 123 wrap_setup (); 124 125 /* parse the args */ 126 optind = 1; 127 while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:W:")) != -1) 128 { 129 switch (c) 130 { 131 case 'A': 132 aflag = 1; 133 break; 134 case 'I': 135 ign_add (optarg, 0); 136 break; 137 case 'W': 138 wrap_add (optarg, 0); 139 break; 140 case 'k': 141 if (options) 142 free (options); 143 options = RCS_check_kflag (optarg); 144 break; 145 case 'l': 146 local = 1; 147 break; 148 case 'R': 149 local = 0; 150 break; 151 case 'Q': 152 case 'q': 153 #ifdef SERVER_SUPPORT 154 /* The CVS 1.5 client sends these options (in addition to 155 Global_option requests), so we must ignore them. */ 156 if (!server_active) 157 #endif 158 error (1, 0, 159 "-q or -Q must be specified before \"%s\"", 160 command_name); 161 break; 162 case 'd': 163 update_build_dirs = 1; 164 break; 165 case 'f': 166 force_tag_match = 0; 167 break; 168 case 'r': 169 tag = optarg; 170 break; 171 case 'D': 172 date = Make_Date (optarg); 173 break; 174 case 'P': 175 update_prune_dirs = 1; 176 break; 177 case 'p': 178 pipeout = 1; 179 noexec = 1; /* so no locks will be created */ 180 break; 181 case 'j': 182 if (join_rev2) 183 error (1, 0, "only two -j options can be specified"); 184 if (join_rev1) 185 join_rev2 = optarg; 186 else 187 join_rev1 = optarg; 188 break; 189 case 'u': 190 #ifdef SERVER_SUPPORT 191 if (server_active) 192 patches = 1; 193 else 194 #endif 195 usage (update_usage); 196 break; 197 case '?': 198 default: 199 usage (update_usage); 200 break; 201 } 202 } 203 argc -= optind; 204 argv += optind; 205 206 #ifdef CLIENT_SUPPORT 207 if (client_active) 208 { 209 /* The first pass does the regular update. If we receive at least 210 one patch which failed, we do a second pass and just fetch 211 those files whose patches failed. */ 212 do 213 { 214 int status; 215 216 start_server (); 217 218 if (local) 219 send_arg("-l"); 220 if (update_build_dirs) 221 send_arg("-d"); 222 if (pipeout) 223 send_arg("-p"); 224 if (!force_tag_match) 225 send_arg("-f"); 226 if (aflag) 227 send_arg("-A"); 228 if (update_prune_dirs) 229 send_arg("-P"); 230 client_prune_dirs = update_prune_dirs; 231 option_with_arg ("-r", tag); 232 if (options && options[0] != '\0') 233 send_arg (options); 234 if (date) 235 client_senddate (date); 236 if (join_rev1) 237 option_with_arg ("-j", join_rev1); 238 if (join_rev2) 239 option_with_arg ("-j", join_rev2); 240 wrap_send (); 241 242 /* If the server supports the command "update-patches", that means 243 that it knows how to handle the -u argument to update, which 244 means to send patches instead of complete files. */ 245 if (failed_patches == NULL) 246 { 247 #ifndef DONT_USE_PATCH 248 /* Systems which don't have the patch program ported to them 249 will want to define DONT_USE_PATCH; then CVS won't try to 250 invoke patch. */ 251 if (supported_request ("update-patches")) 252 send_arg ("-u"); 253 #endif 254 } 255 256 if (failed_patches == NULL) 257 { 258 send_file_names (argc, argv, SEND_EXPAND_WILD); 259 send_files (argc, argv, local, aflag); 260 } 261 else 262 { 263 int i; 264 265 (void) printf ("%s client: refetching unpatchable files\n", 266 program_name); 267 268 if (toplevel_wd[0] != '\0' 269 && CVS_CHDIR (toplevel_wd) < 0) 270 { 271 error (1, errno, "could not chdir to %s", toplevel_wd); 272 } 273 274 for (i = 0; i < failed_patches_count; i++) 275 (void) unlink_file (failed_patches[i]); 276 send_file_names (failed_patches_count, failed_patches, 0); 277 send_files (failed_patches_count, failed_patches, local, 278 aflag); 279 } 280 281 failed_patches = NULL; 282 failed_patches_count = 0; 283 284 send_to_server ("update\012", 0); 285 286 status = get_responses_and_close (); 287 if (status != 0) 288 return status; 289 290 } while (failed_patches != NULL); 291 292 return 0; 293 } 294 #endif 295 296 if (tag != NULL) 297 tag_check_valid (tag, argc, argv, local, aflag, ""); 298 if (join_rev1 != NULL) 299 tag_check_valid_join (join_rev1, argc, argv, local, aflag, ""); 300 if (join_rev2 != NULL) 301 tag_check_valid_join (join_rev2, argc, argv, local, aflag, ""); 302 303 /* 304 * If we are updating the entire directory (for real) and building dirs 305 * as we go, we make sure there is no static entries file and write the 306 * tag file as appropriate 307 */ 308 if (argc <= 0 && !pipeout) 309 { 310 if (update_build_dirs) 311 { 312 if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) 313 error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); 314 #ifdef SERVER_SUPPORT 315 if (server_active) 316 server_clear_entstat (".", Name_Repository (NULL, NULL)); 317 #endif 318 } 319 320 /* keep the CVS/Tag file current with the specified arguments */ 321 if (aflag || tag || date) 322 { 323 WriteTag ((char *) NULL, tag, date); 324 #ifdef SERVER_SUPPORT 325 if (server_active) 326 server_set_sticky (".", Name_Repository (NULL, NULL), tag, date); 327 #endif 328 } 329 } 330 331 /* look for files/dirs locally and in the repository */ 332 which = W_LOCAL | W_REPOS; 333 334 /* look in the attic too if a tag or date is specified */ 335 if (tag != NULL || date != NULL || joining()) 336 which |= W_ATTIC; 337 338 /* call the command line interface */ 339 err = do_update (argc, argv, options, tag, date, force_tag_match, 340 local, update_build_dirs, aflag, update_prune_dirs, 341 pipeout, which, join_rev1, join_rev2, (char *) NULL); 342 343 /* free the space Make_Date allocated if necessary */ 344 if (date != NULL) 345 free (date); 346 347 return (err); 348 } 349 350 /* 351 * Command line interface to update (used by checkout) 352 */ 353 int 354 do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, 355 xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir) 356 int argc; 357 char **argv; 358 char *xoptions; 359 char *xtag; 360 char *xdate; 361 int xforce; 362 int local; 363 int xbuild; 364 int xaflag; 365 int xprune; 366 int xpipeout; 367 int which; 368 char *xjoin_rev1; 369 char *xjoin_rev2; 370 char *preload_update_dir; 371 { 372 int err = 0; 373 char *cp; 374 375 /* fill in the statics */ 376 options = xoptions; 377 tag = xtag; 378 date = xdate; 379 force_tag_match = xforce; 380 update_build_dirs = xbuild; 381 aflag = xaflag; 382 update_prune_dirs = xprune; 383 pipeout = xpipeout; 384 385 /* setup the join support */ 386 join_rev1 = xjoin_rev1; 387 join_rev2 = xjoin_rev2; 388 if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL) 389 { 390 *cp++ = '\0'; 391 date_rev1 = Make_Date (cp); 392 } 393 else 394 date_rev1 = (char *) NULL; 395 if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL) 396 { 397 *cp++ = '\0'; 398 date_rev2 = Make_Date (cp); 399 } 400 else 401 date_rev2 = (char *) NULL; 402 403 /* call the recursion processor */ 404 err = start_recursion (update_fileproc, update_filesdone_proc, 405 update_dirent_proc, update_dirleave_proc, NULL, 406 argc, argv, local, which, aflag, 1, 407 preload_update_dir, 1); 408 409 /* see if we need to sleep before returning */ 410 if (last_register_time) 411 { 412 time_t now; 413 414 (void) time (&now); 415 if (now == last_register_time) 416 sleep (1); /* to avoid time-stamp races */ 417 } 418 419 return (err); 420 } 421 422 /* 423 * This is the callback proc for update. It is called for each file in each 424 * directory by the recursion code. The current directory is the local 425 * instantiation. file is the file name we are to operate on. update_dir is 426 * set to the path relative to where we started (for pretty printing). 427 * repository is the repository. entries and srcfiles are the pre-parsed 428 * entries and source control files. 429 * 430 * This routine decides what needs to be done for each file and does the 431 * appropriate magic for checkout 432 */ 433 static int 434 update_fileproc (callerdat, finfo) 435 void *callerdat; 436 struct file_info *finfo; 437 { 438 int retval; 439 Ctype status; 440 Vers_TS *vers; 441 int resurrecting; 442 443 resurrecting = 0; 444 445 status = Classify_File (finfo, tag, date, options, force_tag_match, 446 aflag, &vers, pipeout); 447 if (pipeout) 448 { 449 /* 450 * We just return success without doing anything if any of the really 451 * funky cases occur 452 * 453 * If there is still a valid RCS file, do a regular checkout type 454 * operation 455 */ 456 switch (status) 457 { 458 case T_UNKNOWN: /* unknown file was explicitly asked 459 * about */ 460 case T_REMOVE_ENTRY: /* needs to be un-registered */ 461 case T_ADDED: /* added but not committed */ 462 retval = 0; 463 break; 464 case T_CONFLICT: /* old punt-type errors */ 465 retval = 1; 466 break; 467 case T_UPTODATE: /* file was already up-to-date */ 468 case T_NEEDS_MERGE: /* needs merging */ 469 case T_MODIFIED: /* locally modified */ 470 case T_REMOVED: /* removed but not committed */ 471 case T_CHECKOUT: /* needs checkout */ 472 #ifdef SERVER_SUPPORT 473 case T_PATCH: /* needs patch */ 474 #endif 475 retval = checkout_file (finfo, vers, 0); 476 break; 477 478 default: /* can't ever happen :-) */ 479 error (0, 0, 480 "unknown file status %d for file %s", status, finfo->file); 481 retval = 0; 482 break; 483 } 484 } 485 else 486 { 487 switch (status) 488 { 489 case T_UNKNOWN: /* unknown file was explicitly asked 490 * about */ 491 case T_UPTODATE: /* file was already up-to-date */ 492 retval = 0; 493 break; 494 case T_CONFLICT: /* old punt-type errors */ 495 retval = 1; 496 (void) write_letter (finfo->file, 'C', finfo->update_dir); 497 break; 498 case T_NEEDS_MERGE: /* needs merging */ 499 if (noexec) 500 { 501 retval = 1; 502 (void) write_letter (finfo->file, 'C', finfo->update_dir); 503 } 504 else 505 { 506 if (wrap_merge_is_copy (finfo->file)) 507 /* Should we be warning the user that we are 508 * overwriting the user's copy of the file? */ 509 retval = 510 checkout_file (finfo, vers, 0); 511 else 512 retval = merge_file (finfo, vers); 513 } 514 break; 515 case T_MODIFIED: /* locally modified */ 516 retval = 0; 517 if (vers->ts_conflict) 518 { 519 char *filestamp; 520 int retcode; 521 522 /* 523 * If the timestamp has changed and no conflict indicators 524 * are found, it isn't a 'C' any more. 525 */ 526 #ifdef SERVER_SUPPORT 527 if (server_active) 528 retcode = vers->ts_conflict[0] != '='; 529 else { 530 filestamp = time_stamp (finfo->file); 531 retcode = strcmp (vers->ts_conflict, filestamp); 532 free (filestamp); 533 } 534 #else 535 filestamp = time_stamp (finfo->file); 536 retcode = strcmp (vers->ts_conflict, filestamp); 537 free (filestamp); 538 #endif 539 540 if (retcode) 541 { 542 /* 543 * If the timestamps differ, look for Conflict 544 * indicators to see if 'C' anyway. 545 */ 546 run_setup ("%s", GREP); 547 run_arg (RCS_MERGE_PAT); 548 run_arg (finfo->file); 549 retcode = run_exec (RUN_TTY, DEVNULL, 550 RUN_TTY,RUN_NORMAL); 551 if (retcode == -1) 552 { 553 error (1, errno, 554 "fork failed while examining conflict in `%s'", 555 finfo->fullname); 556 } 557 } 558 if (!retcode) 559 { 560 (void) write_letter (finfo->file, 'C', finfo->update_dir); 561 retval = 1; 562 } 563 else 564 { 565 /* Reregister to clear conflict flag. */ 566 Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, 567 vers->options, vers->tag, 568 vers->date, (char *)0); 569 } 570 } 571 if (!retval) 572 retval = write_letter (finfo->file, 'M', finfo->update_dir); 573 break; 574 #ifdef SERVER_SUPPORT 575 case T_PATCH: /* needs patch */ 576 if (patches) 577 { 578 int docheckout; 579 struct stat file_info; 580 unsigned char checksum[16]; 581 582 retval = patch_file (finfo, 583 vers, &docheckout, 584 &file_info, checksum); 585 if (! docheckout) 586 { 587 if (server_active && retval == 0) 588 server_updated (finfo, vers, 589 SERVER_PATCHED, &file_info, 590 checksum); 591 break; 592 } 593 } 594 /* Fall through. */ 595 /* If we're not running as a server, just check the 596 file out. It's simpler and faster than starting up 597 two new processes (diff and patch). */ 598 /* Fall through. */ 599 #endif 600 case T_CHECKOUT: /* needs checkout */ 601 retval = checkout_file (finfo, vers, 0); 602 #ifdef SERVER_SUPPORT 603 if (server_active && retval == 0) 604 server_updated (finfo, vers, 605 SERVER_UPDATED, (struct stat *) NULL, 606 (unsigned char *) NULL); 607 #endif 608 break; 609 case T_ADDED: /* added but not committed */ 610 retval = write_letter (finfo->file, 'A', finfo->update_dir); 611 break; 612 case T_REMOVED: /* removed but not committed */ 613 retval = write_letter (finfo->file, 'R', finfo->update_dir); 614 break; 615 case T_REMOVE_ENTRY: /* needs to be un-registered */ 616 retval = scratch_file (finfo); 617 #ifdef SERVER_SUPPORT 618 if (server_active && retval == 0) 619 { 620 if (vers->ts_user == NULL) 621 server_scratch_entry_only (); 622 server_updated (finfo, vers, 623 SERVER_UPDATED, (struct stat *) NULL, 624 (unsigned char *) NULL); 625 } 626 #endif 627 break; 628 default: /* can't ever happen :-) */ 629 error (0, 0, 630 "unknown file status %d for file %s", status, finfo->file); 631 retval = 0; 632 break; 633 } 634 } 635 636 /* only try to join if things have gone well thus far */ 637 if (retval == 0 && join_rev1) 638 join_file (finfo, vers); 639 640 /* if this directory has an ignore list, add this file to it */ 641 if (ignlist) 642 { 643 Node *p; 644 645 p = getnode (); 646 p->type = FILES; 647 p->key = xstrdup (finfo->file); 648 if (addnode (ignlist, p) != 0) 649 freenode (p); 650 } 651 652 freevers_ts (&vers); 653 return (retval); 654 } 655 656 static void update_ignproc PROTO ((char *, char *)); 657 658 static void 659 update_ignproc (file, dir) 660 char *file; 661 char *dir; 662 { 663 (void) write_letter (file, '?', dir); 664 } 665 666 /* ARGSUSED */ 667 static int 668 update_filesdone_proc (callerdat, err, repository, update_dir, entries) 669 void *callerdat; 670 int err; 671 char *repository; 672 char *update_dir; 673 List *entries; 674 { 675 /* if this directory has an ignore list, process it then free it */ 676 if (ignlist) 677 { 678 ignore_files (ignlist, entries, update_dir, update_ignproc); 679 dellist (&ignlist); 680 } 681 682 /* Clean up CVS admin dirs if we are export */ 683 if (strcmp (command_name, "export") == 0) 684 { 685 /* I'm not sure the existence_error is actually possible (except 686 in cases where we really should print a message), but since 687 this code used to ignore all errors, I'll play it safe. */ 688 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno)) 689 error (0, errno, "cannot remove %s directory", CVSADM); 690 } 691 #ifdef SERVER_SUPPORT 692 else if (!server_active && !pipeout) 693 #else 694 else if (!pipeout) 695 #endif /* SERVER_SUPPORT */ 696 { 697 /* If there is no CVS/Root file, add one */ 698 if (!isfile (CVSADM_ROOT)) 699 Create_Root ((char *) NULL, CVSroot_original); 700 } 701 702 return (err); 703 } 704 705 /* 706 * update_dirent_proc () is called back by the recursion processor before a 707 * sub-directory is processed for update. In this case, update_dirent proc 708 * will probably create the directory unless -d isn't specified and this is a 709 * new directory. A return code of 0 indicates the directory should be 710 * processed by the recursion code. A return of non-zero indicates the 711 * recursion code should skip this directory. 712 */ 713 static Dtype 714 update_dirent_proc (callerdat, dir, repository, update_dir, entries) 715 void *callerdat; 716 char *dir; 717 char *repository; 718 char *update_dir; 719 List *entries; 720 { 721 if (ignore_directory (update_dir)) 722 { 723 /* print the warm fuzzy message */ 724 if (!quiet) 725 error (0, 0, "Ignoring %s", update_dir); 726 return R_SKIP_ALL; 727 } 728 729 if (!isdir (dir)) 730 { 731 /* if we aren't building dirs, blow it off */ 732 if (!update_build_dirs) 733 return (R_SKIP_ALL); 734 735 if (noexec) 736 { 737 /* ignore the missing dir if -n is specified */ 738 error (0, 0, "New directory `%s' -- ignored", dir); 739 return (R_SKIP_ALL); 740 } 741 else 742 { 743 /* otherwise, create the dir and appropriate adm files */ 744 make_directory (dir); 745 Create_Admin (dir, update_dir, repository, tag, date); 746 Subdir_Register (entries, (char *) NULL, dir); 747 } 748 } 749 /* Do we need to check noexec here? */ 750 else if (!pipeout) 751 { 752 char *cvsadmdir; 753 754 /* The directory exists. Check to see if it has a CVS 755 subdirectory. */ 756 757 cvsadmdir = xmalloc (strlen (dir) + 80); 758 strcpy (cvsadmdir, dir); 759 strcat (cvsadmdir, "/"); 760 strcat (cvsadmdir, CVSADM); 761 762 if (!isdir (cvsadmdir)) 763 { 764 /* We cannot successfully recurse into a directory without a CVS 765 subdirectory. Generally we will have already printed 766 "? foo". */ 767 free (cvsadmdir); 768 return R_SKIP_ALL; 769 } 770 free (cvsadmdir); 771 } 772 773 /* 774 * If we are building dirs and not going to stdout, we make sure there is 775 * no static entries file and write the tag file as appropriate 776 */ 777 if (!pipeout) 778 { 779 if (update_build_dirs) 780 { 781 char tmp[PATH_MAX]; 782 783 (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT); 784 if (unlink_file (tmp) < 0 && ! existence_error (errno)) 785 error (1, errno, "cannot remove file %s", tmp); 786 #ifdef SERVER_SUPPORT 787 if (server_active) 788 server_clear_entstat (update_dir, repository); 789 #endif 790 } 791 792 /* keep the CVS/Tag file current with the specified arguments */ 793 if (aflag || tag || date) 794 { 795 WriteTag (dir, tag, date); 796 #ifdef SERVER_SUPPORT 797 if (server_active) 798 server_set_sticky (update_dir, repository, tag, date); 799 #endif 800 } 801 802 /* initialize the ignore list for this directory */ 803 ignlist = getlist (); 804 } 805 806 /* print the warm fuzzy message */ 807 if (!quiet) 808 error (0, 0, "Updating %s", update_dir); 809 810 return (R_PROCESS); 811 } 812 813 /* 814 * update_dirleave_proc () is called back by the recursion code upon leaving 815 * a directory. It will prune empty directories if needed and will execute 816 * any appropriate update programs. 817 */ 818 /* ARGSUSED */ 819 static int 820 update_dirleave_proc (callerdat, dir, err, update_dir, entries) 821 void *callerdat; 822 char *dir; 823 int err; 824 char *update_dir; 825 List *entries; 826 { 827 FILE *fp; 828 829 /* run the update_prog if there is one */ 830 if (err == 0 && !pipeout && !noexec && 831 (fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL) 832 { 833 char *cp; 834 char *repository; 835 char line[MAXLINELEN]; 836 837 repository = Name_Repository ((char *) NULL, update_dir); 838 if (fgets (line, sizeof (line), fp) != NULL) 839 { 840 if ((cp = strrchr (line, '\n')) != NULL) 841 *cp = '\0'; 842 run_setup ("%s %s", line, repository); 843 (void) printf ("%s %s: Executing '", program_name, command_name); 844 run_print (stdout); 845 (void) printf ("'\n"); 846 (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); 847 } 848 (void) fclose (fp); 849 free (repository); 850 } 851 852 if (strchr (dir, '/') == NULL) 853 { 854 /* FIXME: chdir ("..") loses with symlinks. */ 855 /* Prune empty dirs on the way out - if necessary */ 856 (void) CVS_CHDIR (".."); 857 if (update_prune_dirs && isemptydir (dir)) 858 { 859 /* I'm not sure the existence_error is actually possible (except 860 in cases where we really should print a message), but since 861 this code used to ignore all errors, I'll play it safe. */ 862 if (unlink_file_dir (dir) < 0 && !existence_error (errno)) 863 error (0, errno, "cannot remove %s directory", dir); 864 Subdir_Deregister (entries, (char *) NULL, dir); 865 } 866 } 867 868 return (err); 869 } 870 871 /* 872 * Returns 1 if the argument directory is completely empty, other than the 873 * existence of the CVS directory entry. Zero otherwise. 874 */ 875 static int 876 isemptydir (dir) 877 char *dir; 878 { 879 DIR *dirp; 880 struct dirent *dp; 881 882 if ((dirp = CVS_OPENDIR (dir)) == NULL) 883 { 884 error (0, 0, "cannot open directory %s for empty check", dir); 885 return (0); 886 } 887 while ((dp = readdir (dirp)) != NULL) 888 { 889 if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 && 890 strcmp (dp->d_name, CVSADM) != 0) 891 { 892 (void) closedir (dirp); 893 return (0); 894 } 895 } 896 (void) closedir (dirp); 897 return (1); 898 } 899 900 /* 901 * scratch the Entries file entry associated with a file 902 */ 903 static int 904 scratch_file (finfo) 905 struct file_info *finfo; 906 { 907 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository); 908 Scratch_Entry (finfo->entries, finfo->file); 909 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 910 error (0, errno, "unable to remove %s", finfo->fullname); 911 return (0); 912 } 913 914 /* 915 * Check out a file. 916 */ 917 static int 918 checkout_file (finfo, vers_ts, adding) 919 struct file_info *finfo; 920 Vers_TS *vers_ts; 921 int adding; 922 { 923 char backup[PATH_MAX]; 924 int set_time, retval = 0; 925 int retcode = 0; 926 int status; 927 int file_is_dead; 928 929 /* don't screw with backup files if we're going to stdout */ 930 if (!pipeout) 931 { 932 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); 933 if (isfile (finfo->file)) 934 rename_file (finfo->file, backup); 935 else 936 (void) unlink_file (backup); 937 } 938 939 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs); 940 941 if (!file_is_dead) 942 { 943 /* 944 * if we are checking out to stdout, print a nice message to 945 * stderr, and add the -p flag to the command */ 946 if (pipeout) 947 { 948 if (!quiet) 949 { 950 (void) fprintf (stderr, "\ 951 ===================================================================\n"); 952 (void) fprintf (stderr, "Checking out %s\n", finfo->fullname); 953 (void) fprintf (stderr, "RCS: %s\n", vers_ts->srcfile->path); 954 (void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs); 955 (void) fprintf (stderr, "***************\n"); 956 } 957 } 958 959 status = RCS_checkout (vers_ts->srcfile, 960 pipeout ? NULL : finfo->file, 961 vers_ts->vn_rcs, vers_ts->vn_tag, 962 vers_ts->options, RUN_TTY); 963 } 964 if (file_is_dead || status == 0) 965 { 966 if (!pipeout) 967 { 968 Vers_TS *xvers_ts; 969 970 if (cvswrite == TRUE 971 && !file_is_dead 972 && !fileattr_get (finfo->file, "_watched")) 973 xchmod (finfo->file, 1); 974 975 { 976 /* A newly checked out file is never under the spell 977 of "cvs edit". If we think we were editing it 978 from a previous life, clean up. Would be better to 979 check for same the working directory instead of 980 same user, but that is hairy. */ 981 982 struct addremove_args args; 983 984 editor_set (finfo->file, getcaller (), NULL); 985 986 memset (&args, 0, sizeof args); 987 args.remove_temp = 1; 988 watch_modify_watchers (finfo->file, &args); 989 } 990 991 /* set the time from the RCS file iff it was unknown before */ 992 if (vers_ts->vn_user == NULL || 993 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0) 994 { 995 set_time = 1; 996 } 997 else 998 set_time = 0; 999 1000 wrap_fromcvs_process_file (finfo->file); 1001 1002 xvers_ts = Version_TS (finfo, options, tag, date, 1003 force_tag_match, set_time); 1004 if (strcmp (xvers_ts->options, "-V4") == 0) 1005 xvers_ts->options[0] = '\0'; 1006 1007 (void) time (&last_register_time); 1008 1009 if (file_is_dead) 1010 { 1011 if (xvers_ts->vn_user != NULL) 1012 { 1013 error (0, 0, 1014 "warning: %s is not (any longer) pertinent", 1015 finfo->fullname); 1016 } 1017 Scratch_Entry (finfo->entries, finfo->file); 1018 #ifdef SERVER_SUPPORT 1019 if (server_active && xvers_ts->ts_user == NULL) 1020 server_scratch_entry_only (); 1021 #endif 1022 /* FIXME: Rather than always unlink'ing, and ignoring the 1023 existence_error, we should do the unlink only if 1024 vers_ts->ts_user is non-NULL. Then there would be no 1025 need to ignore an existence_error (for example, if the 1026 user removes the file while we are running). */ 1027 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 1028 { 1029 error (0, errno, "cannot remove %s", finfo->fullname); 1030 } 1031 } 1032 else 1033 Register (finfo->entries, finfo->file, 1034 adding ? "0" : xvers_ts->vn_rcs, 1035 xvers_ts->ts_user, xvers_ts->options, 1036 xvers_ts->tag, xvers_ts->date, 1037 (char *)0); /* Clear conflict flag on fresh checkout */ 1038 1039 /* fix up the vers structure, in case it is used by join */ 1040 if (join_rev1) 1041 { 1042 if (vers_ts->vn_user != NULL) 1043 free (vers_ts->vn_user); 1044 if (vers_ts->vn_rcs != NULL) 1045 free (vers_ts->vn_rcs); 1046 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs); 1047 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs); 1048 } 1049 1050 /* If this is really Update and not Checkout, recode history */ 1051 if (strcmp (command_name, "update") == 0) 1052 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file, 1053 finfo->repository); 1054 1055 freevers_ts (&xvers_ts); 1056 1057 if (!really_quiet && !file_is_dead) 1058 { 1059 write_letter (finfo->file, 'U', finfo->update_dir); 1060 } 1061 } 1062 } 1063 else 1064 { 1065 int old_errno = errno; /* save errno value over the rename */ 1066 1067 if (!pipeout && isfile (backup)) 1068 rename_file (backup, finfo->file); 1069 1070 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, 1071 "could not check out %s", finfo->fullname); 1072 1073 retval = retcode; 1074 } 1075 1076 if (!pipeout) 1077 (void) unlink_file (backup); 1078 1079 return (retval); 1080 } 1081 1082 #ifdef SERVER_SUPPORT 1083 /* Patch a file. Runs rcsdiff. This is only done when running as the 1084 * server. The hope is that the diff will be smaller than the file 1085 * itself. 1086 */ 1087 static int 1088 patch_file (finfo, vers_ts, docheckout, file_info, checksum) 1089 struct file_info *finfo; 1090 Vers_TS *vers_ts; 1091 int *docheckout; 1092 struct stat *file_info; 1093 unsigned char *checksum; 1094 { 1095 char backup[PATH_MAX]; 1096 char file1[PATH_MAX]; 1097 char file2[PATH_MAX]; 1098 int retval = 0; 1099 int retcode = 0; 1100 int fail; 1101 long file_size; 1102 FILE *e; 1103 1104 *docheckout = 0; 1105 1106 if (pipeout || joining ()) 1107 { 1108 *docheckout = 1; 1109 return 0; 1110 } 1111 1112 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); 1113 if (isfile (finfo->file)) 1114 rename_file (finfo->file, backup); 1115 else 1116 (void) unlink_file (backup); 1117 1118 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file); 1119 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file); 1120 1121 fail = 0; 1122 1123 /* We need to check out both revisions first, to see if either one 1124 has a trailing newline. Because of this, we don't use rcsdiff, 1125 but just use diff. */ 1126 if (noexec) 1127 retcode = 0; 1128 else 1129 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL, 1130 vers_ts->vn_user, (char *) NULL, 1131 vers_ts->options, file1); 1132 if (retcode != 0) 1133 fail = 1; 1134 else 1135 { 1136 e = CVS_FOPEN (file1, "r"); 1137 if (e == NULL) 1138 fail = 1; 1139 else 1140 { 1141 if (fseek (e, (long) -1, SEEK_END) == 0 1142 && getc (e) != '\n') 1143 { 1144 fail = 1; 1145 } 1146 fclose (e); 1147 } 1148 } 1149 1150 if (! fail) 1151 { 1152 /* Check it out into finfo->file, and then move to file2, so that we 1153 can get the right modes into *FILE_INFO. We can't check it 1154 out directly into file2 because co doesn't understand how 1155 to do that. */ 1156 retcode = RCS_checkout (vers_ts->srcfile, finfo->file, 1157 vers_ts->vn_rcs, (char *) NULL, 1158 vers_ts->options, RUN_TTY); 1159 if (retcode != 0) 1160 fail = 1; 1161 else 1162 { 1163 if (!isreadable (finfo->file)) 1164 { 1165 /* File is dead. */ 1166 fail = 1; 1167 } 1168 else 1169 { 1170 rename_file (finfo->file, file2); 1171 if (cvswrite == TRUE 1172 && !fileattr_get (finfo->file, "_watched")) 1173 xchmod (file2, 1); 1174 e = CVS_FOPEN (file2, "r"); 1175 if (e == NULL) 1176 fail = 1; 1177 else 1178 { 1179 struct MD5Context context; 1180 int nl; 1181 unsigned char buf[8192]; 1182 unsigned len; 1183 1184 nl = 0; 1185 1186 /* Compute the MD5 checksum and make sure there is 1187 a trailing newline. */ 1188 MD5Init (&context); 1189 while ((len = fread (buf, 1, sizeof buf, e)) != 0) 1190 { 1191 nl = buf[len - 1] == '\n'; 1192 MD5Update (&context, buf, len); 1193 } 1194 MD5Final (checksum, &context); 1195 1196 if (ferror (e) || ! nl) 1197 { 1198 fail = 1; 1199 } 1200 1201 fseek(e, 0L, SEEK_END); 1202 file_size = ftell(e); 1203 1204 fclose (e); 1205 } 1206 } 1207 } 1208 } 1209 1210 retcode = 0; 1211 if (! fail) 1212 { 1213 /* FIXME: This whole thing with diff/patch is rather more 1214 convoluted than necessary (lots of forks and execs, need to 1215 worry about versions of diff and patch, etc.). Also, we 1216 send context lines which aren't needed (in the rare case in 1217 which the diff doesn't apply, the checksum would catches it). 1218 Solution perhaps is to librarify the RCS routines which apply 1219 deltas or something equivalent. */ 1220 /* This is -c, not -u, because we have no way of knowing which 1221 DIFF is in use. */ 1222 run_setup ("%s -c %s %s", DIFF, file1, file2); 1223 1224 /* A retcode of 0 means no differences. 1 means some differences. */ 1225 if ((retcode = run_exec (RUN_TTY, finfo->file, RUN_TTY, RUN_NORMAL)) != 0 1226 && retcode != 1) 1227 { 1228 fail = 1; 1229 } 1230 else 1231 { 1232 #define BINARY "Binary" 1233 char buf[sizeof BINARY]; 1234 unsigned int c; 1235 1236 /* Check the diff output to make sure patch will be handle it. */ 1237 e = CVS_FOPEN (finfo->file, "r"); 1238 if (e == NULL) 1239 error (1, errno, "could not open diff output file %s", 1240 finfo->fullname); 1241 c = fread (buf, 1, sizeof BINARY - 1, e); 1242 buf[c] = '\0'; 1243 if (strcmp (buf, BINARY) == 0) 1244 { 1245 /* These are binary files. We could use diff -a, but 1246 patch can't handle that. */ 1247 fail = 1; 1248 } 1249 else { 1250 /* 1251 * Don't send a diff if just sending the entire file 1252 * would be smaller 1253 */ 1254 fseek(e, 0L, SEEK_END); 1255 if (file_size < ftell(e)) 1256 fail = 1; 1257 } 1258 1259 fclose (e); 1260 } 1261 } 1262 1263 if (! fail) 1264 { 1265 Vers_TS *xvers_ts; 1266 1267 /* This stuff is just copied blindly from checkout_file. I 1268 don't really know what it does. */ 1269 xvers_ts = Version_TS (finfo, options, tag, date, 1270 force_tag_match, 0); 1271 if (strcmp (xvers_ts->options, "-V4") == 0) 1272 xvers_ts->options[0] = '\0'; 1273 1274 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs, 1275 xvers_ts->ts_user, xvers_ts->options, 1276 xvers_ts->tag, xvers_ts->date, NULL); 1277 1278 if ( CVS_STAT (file2, file_info) < 0) 1279 error (1, errno, "could not stat %s", file2); 1280 1281 /* If this is really Update and not Checkout, recode history */ 1282 if (strcmp (command_name, "update") == 0) 1283 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, finfo->file, 1284 finfo->repository); 1285 1286 freevers_ts (&xvers_ts); 1287 1288 if (!really_quiet) 1289 { 1290 write_letter (finfo->file, 'P', finfo->update_dir); 1291 } 1292 } 1293 else 1294 { 1295 int old_errno = errno; /* save errno value over the rename */ 1296 1297 if (isfile (backup)) 1298 rename_file (backup, finfo->file); 1299 1300 if (retcode != 0 && retcode != 1) 1301 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, 1302 "could not diff %s", finfo->fullname); 1303 1304 *docheckout = 1; 1305 retval = retcode; 1306 } 1307 1308 (void) unlink_file (backup); 1309 (void) unlink_file (file1); 1310 (void) unlink_file (file2); 1311 1312 return (retval); 1313 } 1314 #endif 1315 1316 /* 1317 * Several of the types we process only print a bit of information consisting 1318 * of a single letter and the name. 1319 */ 1320 static int 1321 write_letter (file, letter, update_dir) 1322 char *file; 1323 int letter; 1324 char *update_dir; 1325 { 1326 if (!really_quiet) 1327 { 1328 char buf[2]; 1329 buf[0] = letter; 1330 buf[1] = ' '; 1331 cvs_output (buf, 2); 1332 if (update_dir[0]) 1333 { 1334 cvs_output (update_dir, 0); 1335 cvs_output ("/", 1); 1336 } 1337 cvs_output (file, 0); 1338 cvs_output ("\n", 1); 1339 } 1340 return (0); 1341 } 1342 1343 /* 1344 * Do all the magic associated with a file which needs to be merged 1345 */ 1346 static int 1347 merge_file (finfo, vers) 1348 struct file_info *finfo; 1349 Vers_TS *vers; 1350 { 1351 char backup[PATH_MAX]; 1352 int status; 1353 int retcode = 0; 1354 1355 /* 1356 * The users currently modified file is moved to a backup file name 1357 * ".#filename.version", so that it will stay around for a few days 1358 * before being automatically removed by some cron daemon. The "version" 1359 * is the version of the file that the user was most up-to-date with 1360 * before the merge. 1361 */ 1362 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); 1363 1364 (void) unlink_file (backup); 1365 copy_file (finfo->file, backup); 1366 xchmod (finfo->file, 1); 1367 1368 if (strcmp (vers->options, "-kb") == 0) 1369 { 1370 /* For binary files, a merge is always a conflict. We give the 1371 user the two files, and let them resolve it. It is possible 1372 that we should require a "touch foo" or similar step before 1373 we allow a checkin. */ 1374 status = checkout_file (finfo, vers, 0); 1375 #ifdef SERVER_SUPPORT 1376 /* Send the new contents of the file before the message. If we 1377 wanted to be totally correct, we would have the client write 1378 the message only after the file has safely been written. */ 1379 if (server_active) 1380 { 1381 server_copy_file (finfo->file, finfo->update_dir, 1382 finfo->repository, backup); 1383 server_updated (finfo, vers, SERVER_MERGED, 1384 (struct stat *) NULL, (unsigned char *) NULL); 1385 } 1386 #endif 1387 error (0, 0, "binary file needs merge"); 1388 error (0, 0, "revision %s from repository is now in %s", 1389 vers->vn_rcs, finfo->fullname); 1390 error (0, 0, "file from working directory is now in %s", backup); 1391 write_letter (finfo->file, 'C', finfo->update_dir); 1392 1393 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1394 return 0; 1395 } 1396 1397 status = RCS_merge(vers->srcfile->path, 1398 vers->options, vers->vn_user, vers->vn_rcs); 1399 if (status != 0 && status != 1) 1400 { 1401 error (0, status == -1 ? errno : 0, 1402 "could not merge revision %s of %s", vers->vn_user, finfo->fullname); 1403 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1404 finfo->fullname, backup); 1405 rename_file (backup, finfo->file); 1406 return (1); 1407 } 1408 1409 if (strcmp (vers->options, "-V4") == 0) 1410 vers->options[0] = '\0'; 1411 (void) time (&last_register_time); 1412 { 1413 char *cp = 0; 1414 1415 if (status) 1416 cp = time_stamp (finfo->file); 1417 Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, vers->options, 1418 vers->tag, vers->date, cp); 1419 if (cp) 1420 free (cp); 1421 } 1422 1423 /* fix up the vers structure, in case it is used by join */ 1424 if (join_rev1) 1425 { 1426 if (vers->vn_user != NULL) 1427 free (vers->vn_user); 1428 vers->vn_user = xstrdup (vers->vn_rcs); 1429 } 1430 1431 #ifdef SERVER_SUPPORT 1432 /* Send the new contents of the file before the message. If we 1433 wanted to be totally correct, we would have the client write 1434 the message only after the file has safely been written. */ 1435 if (server_active) 1436 { 1437 server_copy_file (finfo->file, finfo->update_dir, finfo->repository, 1438 backup); 1439 server_updated (finfo, vers, SERVER_MERGED, 1440 (struct stat *) NULL, (unsigned char *) NULL); 1441 } 1442 #endif 1443 1444 if (!noexec && !xcmp (backup, finfo->file)) 1445 { 1446 printf ("%s already contains the differences between %s and %s\n", 1447 finfo->fullname, vers->vn_user, vers->vn_rcs); 1448 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1449 return (0); 1450 } 1451 1452 if (status == 1) 1453 { 1454 if (!noexec) 1455 error (0, 0, "conflicts found in %s", finfo->fullname); 1456 1457 write_letter (finfo->file, 'C', finfo->update_dir); 1458 1459 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1460 1461 } 1462 else if (retcode == -1) 1463 { 1464 error (1, errno, "fork failed while examining update of %s", finfo->fullname); 1465 } 1466 else 1467 { 1468 write_letter (finfo->file, 'M', finfo->update_dir); 1469 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1470 } 1471 return (0); 1472 } 1473 1474 /* 1475 * Do all the magic associated with a file which needs to be joined 1476 * (-j option) 1477 */ 1478 static void 1479 join_file (finfo, vers) 1480 struct file_info *finfo; 1481 Vers_TS *vers; 1482 { 1483 char backup[PATH_MAX]; 1484 char *options; 1485 int status; 1486 1487 char *rev1; 1488 char *rev2; 1489 char *jrev1; 1490 char *jrev2; 1491 char *jdate1; 1492 char *jdate2; 1493 1494 jrev1 = join_rev1; 1495 jrev2 = join_rev2; 1496 jdate1 = date_rev1; 1497 jdate2 = date_rev2; 1498 1499 if (wrap_merge_is_copy (finfo->file)) 1500 { 1501 error (0, 0, 1502 "Cannot merge %s because it is a merge-by-copy file.", 1503 finfo->fullname); 1504 return; 1505 } 1506 1507 /* Determine if we need to do anything at all. */ 1508 if (vers->srcfile == NULL || 1509 vers->srcfile->path == NULL) 1510 { 1511 return; 1512 } 1513 1514 /* If only one join revision is specified, it becomes the second 1515 revision. */ 1516 if (jrev2 == NULL) 1517 { 1518 jrev2 = jrev1; 1519 jrev1 = NULL; 1520 jdate2 = jdate1; 1521 jdate1 = NULL; 1522 } 1523 1524 /* Convert the second revision, walking branches and dates. */ 1525 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL); 1526 1527 /* If this is a merge of two revisions, get the first revision. 1528 If only one join tag was specified, then the first revision is 1529 the greatest common ancestor of the second revision and the 1530 working file. */ 1531 if (jrev1 != NULL) 1532 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL); 1533 else 1534 { 1535 /* Note that we use vn_rcs here, since vn_user may contain a 1536 special string such as "-nn". */ 1537 if (vers->vn_rcs == NULL) 1538 rev1 = NULL; 1539 else if (rev2 == NULL) 1540 { 1541 /* This means that the file never existed on the branch. 1542 It does not mean that the file was removed on the 1543 branch: that case is represented by a dead rev2. If 1544 the file never existed on the branch, then we have 1545 nothing to merge, so we just return. */ 1546 return; 1547 } 1548 else 1549 rev1 = gca (vers->vn_rcs, rev2); 1550 } 1551 1552 /* Handle a nonexistent or dead merge target. */ 1553 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2)) 1554 { 1555 char *mrev; 1556 1557 if (rev2 != NULL) 1558 free (rev2); 1559 1560 /* If the first revision doesn't exist either, then there is 1561 no change between the two revisions, so we don't do 1562 anything. */ 1563 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) 1564 { 1565 if (rev1 != NULL) 1566 free (rev1); 1567 return; 1568 } 1569 1570 /* If we are merging two revisions, then the file was removed 1571 between the first revision and the second one. In this 1572 case we want to mark the file for removal. 1573 1574 If we are merging one revision, then the file has been 1575 removed between the greatest common ancestor and the merge 1576 revision. From the perspective of the branch on to which 1577 we ar emerging, which may be the trunk, either 1) the file 1578 does not currently exist on the target, or 2) the file has 1579 not been modified on the target branch since the greatest 1580 common ancestor, or 3) the file has been modified on the 1581 target branch since the greatest common ancestor. In case 1582 1 there is nothing to do. In case 2 we mark the file for 1583 removal. In case 3 we have a conflict. 1584 1585 Note that the handling is slightly different depending upon 1586 whether one or two join targets were specified. If two 1587 join targets were specified, we don't check whether the 1588 file was modified since a given point. My reasoning is 1589 that if you ask for an explicit merge between two tags, 1590 then you want to merge in whatever was changed between 1591 those two tags. If a file was removed between the two 1592 tags, then you want it to be removed. However, if you ask 1593 for a merge of a branch, then you want to merge in all 1594 changes which were made on the branch. If a file was 1595 removed on the branch, that is a change to the file. If 1596 the file was also changed on the main line, then that is 1597 also a change. These two changes--the file removal and the 1598 modification--must be merged. This is a conflict. */ 1599 1600 /* If the user file is dead, or does not exist, or has been 1601 marked for removal, then there is nothing to do. */ 1602 if (vers->vn_user == NULL 1603 || vers->vn_user[0] == '-' 1604 || RCS_isdead (vers->srcfile, vers->vn_user)) 1605 { 1606 if (rev1 != NULL) 1607 free (rev1); 1608 return; 1609 } 1610 1611 /* If the user file has been marked for addition, or has been 1612 locally modified, then we have a conflict which we can not 1613 resolve. No_Difference will already have been called in 1614 this case, so comparing the timestamps is sufficient to 1615 determine whether the file is locally modified. */ 1616 if (strcmp (vers->vn_user, "0") == 0 1617 || (vers->ts_user != NULL 1618 && strcmp (vers->ts_user, vers->ts_rcs) != 0)) 1619 { 1620 if (jdate2 != NULL) 1621 error (0, 0, 1622 "file %s is locally modified, but has been removed in revision %s as of %s", 1623 finfo->fullname, jrev2, jdate2); 1624 else 1625 error (0, 0, 1626 "file %s is locally modified, but has been removed in revision %s", 1627 finfo->fullname, jrev2); 1628 1629 /* FIXME: Should we arrange to return a non-zero exit 1630 status? */ 1631 1632 if (rev1 != NULL) 1633 free (rev1); 1634 1635 return; 1636 } 1637 1638 /* If only one join tag was specified, and the user file has 1639 been changed since the greatest common ancestor (rev1), 1640 then there is a conflict we can not resolve. See above for 1641 the rationale. */ 1642 if (join_rev2 == NULL 1643 && strcmp (rev1, vers->vn_user) != 0) 1644 { 1645 if (jdate2 != NULL) 1646 error (0, 0, 1647 "file %s has been modified, but has been removed in revision %s as of %s", 1648 finfo->fullname, jrev2, jdate2); 1649 else 1650 error (0, 0, 1651 "file %s has been modified, but has been removed in revision %s", 1652 finfo->fullname, jrev2); 1653 1654 /* FIXME: Should we arrange to return a non-zero exit 1655 status? */ 1656 1657 if (rev1 != NULL) 1658 free (rev1); 1659 1660 return; 1661 } 1662 1663 if (rev1 != NULL) 1664 free (rev1); 1665 1666 /* The user file exists and has not been modified. Mark it 1667 for removal. FIXME: If we are doing a checkout, this has 1668 the effect of first checking out the file, and then 1669 removing it. It would be better to just register the 1670 removal. */ 1671 #ifdef SERVER_SUPPORT 1672 if (server_active) 1673 { 1674 server_scratch (finfo->file); 1675 server_updated (finfo, vers, SERVER_UPDATED, (struct stat *) NULL, 1676 (unsigned char *) NULL); 1677 } 1678 #endif 1679 mrev = xmalloc (strlen (vers->vn_user) + 2); 1680 sprintf (mrev, "-%s", vers->vn_user); 1681 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs, 1682 vers->options, vers->tag, vers->date, vers->ts_conflict); 1683 free (mrev); 1684 /* We need to check existence_error here because if we are 1685 running as the server, and the file is up to date in the 1686 working directory, the client will not have sent us a copy. */ 1687 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 1688 error (0, errno, "cannot remove file %s", finfo->fullname); 1689 #ifdef SERVER_SUPPORT 1690 if (server_active) 1691 server_checked_in (finfo->file, finfo->update_dir, 1692 finfo->repository); 1693 #endif 1694 if (! really_quiet) 1695 error (0, 0, "scheduling %s for removal", finfo->fullname); 1696 1697 return; 1698 } 1699 1700 /* If the target of the merge is the same as the working file 1701 revision, then there is nothing to do. */ 1702 if (vers->vn_user != NULL && strcmp (rev2, vers->vn_user) == 0) 1703 { 1704 if (rev1 != NULL) 1705 free (rev1); 1706 free (rev2); 1707 return; 1708 } 1709 1710 /* If rev1 is dead or does not exist, then the file was added 1711 between rev1 and rev2. */ 1712 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) 1713 { 1714 if (rev1 != NULL) 1715 free (rev1); 1716 free (rev2); 1717 1718 /* If the file does not exist in the working directory, then 1719 we can just check out the new revision and mark it for 1720 addition. */ 1721 if (vers->vn_user == NULL) 1722 { 1723 Vers_TS *xvers; 1724 1725 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); 1726 1727 /* FIXME: If checkout_file fails, we should arrange to 1728 return a non-zero exit status. */ 1729 status = checkout_file (finfo, xvers, 1); 1730 1731 #ifdef SERVER_SUPPORT 1732 if (server_active && status == 0) 1733 server_updated (finfo, xvers, 1734 SERVER_UPDATED, (struct stat *) NULL, 1735 (unsigned char *) NULL); 1736 #endif 1737 1738 freevers_ts (&xvers); 1739 1740 return; 1741 } 1742 1743 /* The file currently exists in the working directory, so we 1744 have a conflict which we can not resolve. Note that this 1745 is true even if the file is marked for addition or removal. */ 1746 1747 if (jdate2 != NULL) 1748 error (0, 0, 1749 "file %s exists, but has been added in revision %s as of %s", 1750 finfo->fullname, jrev2, jdate2); 1751 else 1752 error (0, 0, 1753 "file %s exists, but has been added in revision %s", 1754 finfo->fullname, jrev2); 1755 1756 return; 1757 } 1758 1759 /* If the two merge revisions are the same, then there is nothing 1760 to do. */ 1761 if (strcmp (rev1, rev2) == 0) 1762 { 1763 free (rev1); 1764 free (rev2); 1765 return; 1766 } 1767 1768 /* If there is no working file, then we can't do the merge. */ 1769 if (vers->vn_user == NULL) 1770 { 1771 free (rev1); 1772 free (rev2); 1773 1774 if (jdate2 != NULL) 1775 error (0, 0, 1776 "file %s is present in revision %s as of %s", 1777 finfo->fullname, jrev2, jdate2); 1778 else 1779 error (0, 0, 1780 "file %s is present in revision %s", 1781 finfo->fullname, jrev2); 1782 1783 /* FIXME: Should we arrange to return a non-zero exit status? */ 1784 1785 return; 1786 } 1787 1788 #ifdef SERVER_SUPPORT 1789 if (server_active && !isreadable (finfo->file)) 1790 { 1791 int retcode; 1792 /* The file is up to date. Need to check out the current contents. */ 1793 retcode = RCS_checkout (vers->srcfile, finfo->file, 1794 vers->vn_user, (char *) NULL, 1795 (char *) NULL, RUN_TTY); 1796 if (retcode != 0) 1797 error (1, retcode == -1 ? errno : 0, 1798 "failed to check out %s file", finfo->fullname); 1799 } 1800 #endif 1801 1802 /* 1803 * The users currently modified file is moved to a backup file name 1804 * ".#filename.version", so that it will stay around for a few days 1805 * before being automatically removed by some cron daemon. The "version" 1806 * is the version of the file that the user was most up-to-date with 1807 * before the merge. 1808 */ 1809 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); 1810 1811 (void) unlink_file (backup); 1812 copy_file (finfo->file, backup); 1813 xchmod (finfo->file, 1); 1814 1815 options = vers->options; 1816 #ifdef HAVE_RCS5 1817 #if 0 1818 if (*options == '\0') 1819 options = "-kk"; /* to ignore keyword expansions */ 1820 #endif 1821 #endif 1822 1823 status = RCS_merge (vers->srcfile->path, options, rev1, rev2); 1824 if (status != 0 && status != 1) 1825 { 1826 error (0, status == -1 ? errno : 0, 1827 "could not merge revision %s of %s", rev2, finfo->fullname); 1828 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1829 finfo->fullname, backup); 1830 rename_file (backup, finfo->file); 1831 } 1832 free (rev1); 1833 free (rev2); 1834 1835 #ifdef SERVER_SUPPORT 1836 /* 1837 * If we're in server mode, then we need to re-register the file 1838 * even if there were no conflicts (status == 0). 1839 * This tells server_updated() to send the modified file back to 1840 * the client. 1841 */ 1842 if (status == 1 || (status == 0 && server_active)) 1843 #else 1844 if (status == 1) 1845 #endif 1846 { 1847 char *cp = 0; 1848 1849 if (status) 1850 cp = time_stamp (finfo->file); 1851 Register (finfo->entries, finfo->file, 1852 vers->vn_rcs, vers->ts_rcs, vers->options, 1853 vers->tag, vers->date, cp); 1854 if (cp) 1855 free(cp); 1856 } 1857 1858 #ifdef SERVER_SUPPORT 1859 if (server_active) 1860 { 1861 server_copy_file (finfo->file, finfo->update_dir, finfo->repository, 1862 backup); 1863 server_updated (finfo, vers, SERVER_MERGED, 1864 (struct stat *) NULL, (unsigned char *) NULL); 1865 } 1866 #endif 1867 } 1868 1869 int 1870 joining () 1871 { 1872 return (join_rev1 != NULL); 1873 } 1874