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 #include "savecwd.h" 38 #ifdef SERVER_SUPPORT 39 #include "md5.h" 40 #endif 41 #include "watch.h" 42 #include "fileattr.h" 43 #include "edit.h" 44 45 static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts, 46 int adding)); 47 #ifdef SERVER_SUPPORT 48 static int patch_file PROTO ((struct file_info *finfo, 49 Vers_TS *vers_ts, 50 int *docheckout, struct stat *file_info, 51 unsigned char *checksum)); 52 #endif 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, update_build_dirs); 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 != NULL 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, update_build_dirs); 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 /* The timestamps differ. But if there are conflict 543 markers print 'C' anyway. */ 544 retcode = !file_has_markers (finfo); 545 } 546 547 if (!retcode) 548 { 549 (void) write_letter (finfo->file, 'C', finfo->update_dir); 550 retval = 1; 551 } 552 else 553 { 554 /* Reregister to clear conflict flag. */ 555 Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, 556 vers->options, vers->tag, 557 vers->date, (char *)0); 558 } 559 } 560 if (!retval) 561 retval = write_letter (finfo->file, 'M', finfo->update_dir); 562 break; 563 #ifdef SERVER_SUPPORT 564 case T_PATCH: /* needs patch */ 565 if (patches) 566 { 567 int docheckout; 568 struct stat file_info; 569 unsigned char checksum[16]; 570 571 retval = patch_file (finfo, 572 vers, &docheckout, 573 &file_info, checksum); 574 if (! docheckout) 575 { 576 if (server_active && retval == 0) 577 server_updated (finfo, vers, 578 SERVER_PATCHED, &file_info, 579 checksum); 580 break; 581 } 582 } 583 /* Fall through. */ 584 /* If we're not running as a server, just check the 585 file out. It's simpler and faster than starting up 586 two new processes (diff and patch). */ 587 /* Fall through. */ 588 #endif 589 case T_CHECKOUT: /* needs checkout */ 590 retval = checkout_file (finfo, vers, 0); 591 #ifdef SERVER_SUPPORT 592 if (server_active && retval == 0) 593 server_updated (finfo, vers, 594 SERVER_UPDATED, (struct stat *) NULL, 595 (unsigned char *) NULL); 596 #endif 597 break; 598 case T_ADDED: /* added but not committed */ 599 retval = write_letter (finfo->file, 'A', finfo->update_dir); 600 break; 601 case T_REMOVED: /* removed but not committed */ 602 retval = write_letter (finfo->file, 'R', finfo->update_dir); 603 break; 604 case T_REMOVE_ENTRY: /* needs to be un-registered */ 605 retval = scratch_file (finfo); 606 #ifdef SERVER_SUPPORT 607 if (server_active && retval == 0) 608 { 609 if (vers->ts_user == NULL) 610 server_scratch_entry_only (); 611 server_updated (finfo, vers, 612 SERVER_UPDATED, (struct stat *) NULL, 613 (unsigned char *) NULL); 614 } 615 #endif 616 break; 617 default: /* can't ever happen :-) */ 618 error (0, 0, 619 "unknown file status %d for file %s", status, finfo->file); 620 retval = 0; 621 break; 622 } 623 } 624 625 /* only try to join if things have gone well thus far */ 626 if (retval == 0 && join_rev1) 627 join_file (finfo, vers); 628 629 /* if this directory has an ignore list, add this file to it */ 630 if (ignlist) 631 { 632 Node *p; 633 634 p = getnode (); 635 p->type = FILES; 636 p->key = xstrdup (finfo->file); 637 if (addnode (ignlist, p) != 0) 638 freenode (p); 639 } 640 641 freevers_ts (&vers); 642 return (retval); 643 } 644 645 static void update_ignproc PROTO ((char *, char *)); 646 647 static void 648 update_ignproc (file, dir) 649 char *file; 650 char *dir; 651 { 652 (void) write_letter (file, '?', dir); 653 } 654 655 /* ARGSUSED */ 656 static int 657 update_filesdone_proc (callerdat, err, repository, update_dir, entries) 658 void *callerdat; 659 int err; 660 char *repository; 661 char *update_dir; 662 List *entries; 663 { 664 /* if this directory has an ignore list, process it then free it */ 665 if (ignlist) 666 { 667 ignore_files (ignlist, entries, update_dir, update_ignproc); 668 dellist (&ignlist); 669 } 670 671 /* Clean up CVS admin dirs if we are export */ 672 if (strcmp (command_name, "export") == 0) 673 { 674 /* I'm not sure the existence_error is actually possible (except 675 in cases where we really should print a message), but since 676 this code used to ignore all errors, I'll play it safe. */ 677 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno)) 678 error (0, errno, "cannot remove %s directory", CVSADM); 679 } 680 #ifdef SERVER_SUPPORT 681 else if (!server_active && !pipeout) 682 #else 683 else if (!pipeout) 684 #endif /* SERVER_SUPPORT */ 685 { 686 /* If there is no CVS/Root file, add one */ 687 if (!isfile (CVSADM_ROOT)) 688 Create_Root ((char *) NULL, CVSroot_original); 689 } 690 691 return (err); 692 } 693 694 /* 695 * update_dirent_proc () is called back by the recursion processor before a 696 * sub-directory is processed for update. In this case, update_dirent proc 697 * will probably create the directory unless -d isn't specified and this is a 698 * new directory. A return code of 0 indicates the directory should be 699 * processed by the recursion code. A return of non-zero indicates the 700 * recursion code should skip this directory. 701 */ 702 static Dtype 703 update_dirent_proc (callerdat, dir, repository, update_dir, entries) 704 void *callerdat; 705 char *dir; 706 char *repository; 707 char *update_dir; 708 List *entries; 709 { 710 if (ignore_directory (update_dir)) 711 { 712 /* print the warm fuzzy message */ 713 if (!quiet) 714 error (0, 0, "Ignoring %s", update_dir); 715 return R_SKIP_ALL; 716 } 717 718 if (!isdir (dir)) 719 { 720 /* if we aren't building dirs, blow it off */ 721 if (!update_build_dirs) 722 return (R_SKIP_ALL); 723 724 if (noexec) 725 { 726 /* ignore the missing dir if -n is specified */ 727 error (0, 0, "New directory `%s' -- ignored", dir); 728 return (R_SKIP_ALL); 729 } 730 else 731 { 732 /* otherwise, create the dir and appropriate adm files */ 733 make_directory (dir); 734 Create_Admin (dir, update_dir, repository, tag, date); 735 Subdir_Register (entries, (char *) NULL, dir); 736 } 737 } 738 /* Do we need to check noexec here? */ 739 else if (!pipeout) 740 { 741 char *cvsadmdir; 742 743 /* The directory exists. Check to see if it has a CVS 744 subdirectory. */ 745 746 cvsadmdir = xmalloc (strlen (dir) + 80); 747 strcpy (cvsadmdir, dir); 748 strcat (cvsadmdir, "/"); 749 strcat (cvsadmdir, CVSADM); 750 751 if (!isdir (cvsadmdir)) 752 { 753 /* We cannot successfully recurse into a directory without a CVS 754 subdirectory. Generally we will have already printed 755 "? foo". */ 756 free (cvsadmdir); 757 return R_SKIP_ALL; 758 } 759 free (cvsadmdir); 760 } 761 762 /* 763 * If we are building dirs and not going to stdout, we make sure there is 764 * no static entries file and write the tag file as appropriate 765 */ 766 if (!pipeout) 767 { 768 if (update_build_dirs) 769 { 770 char tmp[PATH_MAX]; 771 772 (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT); 773 if (unlink_file (tmp) < 0 && ! existence_error (errno)) 774 error (1, errno, "cannot remove file %s", tmp); 775 #ifdef SERVER_SUPPORT 776 if (server_active) 777 server_clear_entstat (update_dir, repository); 778 #endif 779 } 780 781 /* keep the CVS/Tag file current with the specified arguments */ 782 if (aflag || tag || date) 783 { 784 WriteTag (dir, tag, date); 785 #ifdef SERVER_SUPPORT 786 if (server_active) 787 server_set_sticky (update_dir, repository, tag, date); 788 #endif 789 } 790 791 /* initialize the ignore list for this directory */ 792 ignlist = getlist (); 793 } 794 795 /* print the warm fuzzy message */ 796 if (!quiet) 797 error (0, 0, "Updating %s", update_dir); 798 799 return (R_PROCESS); 800 } 801 802 /* 803 * update_dirleave_proc () is called back by the recursion code upon leaving 804 * a directory. It will prune empty directories if needed and will execute 805 * any appropriate update programs. 806 */ 807 /* ARGSUSED */ 808 static int 809 update_dirleave_proc (callerdat, dir, err, update_dir, entries) 810 void *callerdat; 811 char *dir; 812 int err; 813 char *update_dir; 814 List *entries; 815 { 816 FILE *fp; 817 818 /* run the update_prog if there is one */ 819 if (err == 0 && !pipeout && !noexec && 820 (fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL) 821 { 822 char *cp; 823 char *repository; 824 char line[MAXLINELEN]; 825 826 repository = Name_Repository ((char *) NULL, update_dir); 827 if (fgets (line, sizeof (line), fp) != NULL) 828 { 829 if ((cp = strrchr (line, '\n')) != NULL) 830 *cp = '\0'; 831 run_setup ("%s %s", line, repository); 832 cvs_output (program_name, 0); 833 cvs_output (" ", 1); 834 cvs_output (command_name, 0); 835 cvs_output (": Executing '", 0); 836 run_print (stdout); 837 cvs_output ("'\n", 0); 838 (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); 839 } 840 (void) fclose (fp); 841 free (repository); 842 } 843 844 if (strchr (dir, '/') == NULL) 845 { 846 /* FIXME: chdir ("..") loses with symlinks. */ 847 /* Prune empty dirs on the way out - if necessary */ 848 (void) CVS_CHDIR (".."); 849 if (update_prune_dirs && isemptydir (dir, 0)) 850 { 851 /* I'm not sure the existence_error is actually possible (except 852 in cases where we really should print a message), but since 853 this code used to ignore all errors, I'll play it safe. */ 854 if (unlink_file_dir (dir) < 0 && !existence_error (errno)) 855 error (0, errno, "cannot remove %s directory", dir); 856 Subdir_Deregister (entries, (char *) NULL, dir); 857 } 858 } 859 860 return (err); 861 } 862 863 static int isremoved PROTO ((Node *, void *)); 864 865 /* Returns 1 if the file indicated by node has been removed. */ 866 static int 867 isremoved (node, closure) 868 Node *node; 869 void *closure; 870 { 871 Entnode *entdata = (Entnode*) node->data; 872 873 /* If the first character of the version is a '-', the file has been 874 removed. */ 875 return (entdata->version && entdata->version[0] == '-') ? 1 : 0; 876 } 877 878 /* Returns 1 if the argument directory is completely empty, other than the 879 existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST 880 and the directory doesn't exist, then just return 0. */ 881 int 882 isemptydir (dir, might_not_exist) 883 char *dir; 884 int might_not_exist; 885 { 886 DIR *dirp; 887 struct dirent *dp; 888 889 if ((dirp = CVS_OPENDIR (dir)) == NULL) 890 { 891 if (might_not_exist && existence_error (errno)) 892 return 0; 893 error (0, errno, "cannot open directory %s for empty check", dir); 894 return (0); 895 } 896 errno = 0; 897 while ((dp = readdir (dirp)) != NULL) 898 { 899 if (strcmp (dp->d_name, ".") != 0 900 && strcmp (dp->d_name, "..") != 0) 901 { 902 if (strcmp (dp->d_name, CVSADM) != 0) 903 { 904 /* An entry other than the CVS directory. The directory 905 is certainly not empty. */ 906 (void) closedir (dirp); 907 return (0); 908 } 909 else 910 { 911 /* The CVS directory entry. We don't have to worry about 912 this unless the Entries file indicates that files have 913 been removed, but not committed, in this directory. 914 (Removing the directory would prevent people from 915 comitting the fact that they removed the files!) */ 916 List *l; 917 int files_removed; 918 struct saved_cwd cwd; 919 920 if (save_cwd (&cwd)) 921 error_exit (); 922 923 if (CVS_CHDIR (dir) < 0) 924 error (1, errno, "cannot change directory to %s", dir); 925 l = Entries_Open (0); 926 files_removed = walklist (l, isremoved, 0); 927 Entries_Close (l); 928 929 if (restore_cwd (&cwd, NULL)) 930 error_exit (); 931 free_cwd (&cwd); 932 933 if (files_removed != 0) 934 { 935 /* There are files that have been removed, but not 936 committed! Do not consider the directory empty. */ 937 (void) closedir (dirp); 938 return (0); 939 } 940 } 941 } 942 errno = 0; 943 } 944 if (errno != 0) 945 { 946 error (0, errno, "cannot read directory %s", dir); 947 (void) closedir (dirp); 948 return (0); 949 } 950 (void) closedir (dirp); 951 return (1); 952 } 953 954 /* 955 * scratch the Entries file entry associated with a file 956 */ 957 static int 958 scratch_file (finfo) 959 struct file_info *finfo; 960 { 961 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository); 962 Scratch_Entry (finfo->entries, finfo->file); 963 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 964 error (0, errno, "unable to remove %s", finfo->fullname); 965 return (0); 966 } 967 968 /* 969 * Check out a file. 970 */ 971 static int 972 checkout_file (finfo, vers_ts, adding) 973 struct file_info *finfo; 974 Vers_TS *vers_ts; 975 int adding; 976 { 977 char backup[PATH_MAX]; 978 int set_time, retval = 0; 979 int retcode = 0; 980 int status; 981 int file_is_dead; 982 983 /* don't screw with backup files if we're going to stdout */ 984 if (!pipeout) 985 { 986 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); 987 if (isfile (finfo->file)) 988 rename_file (finfo->file, backup); 989 else 990 (void) unlink_file (backup); 991 } 992 993 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs); 994 995 if (!file_is_dead) 996 { 997 /* 998 * if we are checking out to stdout, print a nice message to 999 * stderr, and add the -p flag to the command */ 1000 if (pipeout) 1001 { 1002 if (!quiet) 1003 { 1004 cvs_outerr ("\ 1005 ===================================================================\n\ 1006 Checking out ", 0); 1007 cvs_outerr (finfo->fullname, 0); 1008 cvs_outerr ("\n\ 1009 RCS: ", 0); 1010 cvs_outerr (vers_ts->srcfile->path, 0); 1011 cvs_outerr ("\n\ 1012 VERS: ", 0); 1013 cvs_outerr (vers_ts->vn_rcs, 0); 1014 cvs_outerr ("\n***************\n", 0); 1015 } 1016 } 1017 1018 status = RCS_checkout (vers_ts->srcfile, 1019 pipeout ? NULL : finfo->file, 1020 vers_ts->vn_rcs, vers_ts->vn_tag, 1021 vers_ts->options, RUN_TTY); 1022 } 1023 if (file_is_dead || status == 0) 1024 { 1025 if (!pipeout) 1026 { 1027 Vers_TS *xvers_ts; 1028 1029 if (cvswrite == TRUE 1030 && !file_is_dead 1031 && !fileattr_get (finfo->file, "_watched")) 1032 xchmod (finfo->file, 1); 1033 1034 { 1035 /* A newly checked out file is never under the spell 1036 of "cvs edit". If we think we were editing it 1037 from a previous life, clean up. Would be better to 1038 check for same the working directory instead of 1039 same user, but that is hairy. */ 1040 1041 struct addremove_args args; 1042 1043 editor_set (finfo->file, getcaller (), NULL); 1044 1045 memset (&args, 0, sizeof args); 1046 args.remove_temp = 1; 1047 watch_modify_watchers (finfo->file, &args); 1048 } 1049 1050 /* set the time from the RCS file iff it was unknown before */ 1051 if (vers_ts->vn_user == NULL || 1052 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0) 1053 { 1054 set_time = 1; 1055 } 1056 else 1057 set_time = 0; 1058 1059 wrap_fromcvs_process_file (finfo->file); 1060 1061 xvers_ts = Version_TS (finfo, options, tag, date, 1062 force_tag_match, set_time); 1063 if (strcmp (xvers_ts->options, "-V4") == 0) 1064 xvers_ts->options[0] = '\0'; 1065 1066 (void) time (&last_register_time); 1067 1068 if (file_is_dead) 1069 { 1070 if (xvers_ts->vn_user != NULL) 1071 { 1072 error (0, 0, 1073 "warning: %s is not (any longer) pertinent", 1074 finfo->fullname); 1075 } 1076 Scratch_Entry (finfo->entries, finfo->file); 1077 #ifdef SERVER_SUPPORT 1078 if (server_active && xvers_ts->ts_user == NULL) 1079 server_scratch_entry_only (); 1080 #endif 1081 /* FIXME: Rather than always unlink'ing, and ignoring the 1082 existence_error, we should do the unlink only if 1083 vers_ts->ts_user is non-NULL. Then there would be no 1084 need to ignore an existence_error (for example, if the 1085 user removes the file while we are running). */ 1086 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 1087 { 1088 error (0, errno, "cannot remove %s", finfo->fullname); 1089 } 1090 } 1091 else 1092 Register (finfo->entries, finfo->file, 1093 adding ? "0" : xvers_ts->vn_rcs, 1094 xvers_ts->ts_user, xvers_ts->options, 1095 xvers_ts->tag, xvers_ts->date, 1096 (char *)0); /* Clear conflict flag on fresh checkout */ 1097 1098 /* fix up the vers structure, in case it is used by join */ 1099 if (join_rev1) 1100 { 1101 if (vers_ts->vn_user != NULL) 1102 free (vers_ts->vn_user); 1103 if (vers_ts->vn_rcs != NULL) 1104 free (vers_ts->vn_rcs); 1105 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs); 1106 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs); 1107 } 1108 1109 /* If this is really Update and not Checkout, recode history */ 1110 if (strcmp (command_name, "update") == 0) 1111 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file, 1112 finfo->repository); 1113 1114 freevers_ts (&xvers_ts); 1115 1116 if (!really_quiet && !file_is_dead) 1117 { 1118 write_letter (finfo->file, 'U', finfo->update_dir); 1119 } 1120 } 1121 } 1122 else 1123 { 1124 int old_errno = errno; /* save errno value over the rename */ 1125 1126 if (!pipeout && isfile (backup)) 1127 rename_file (backup, finfo->file); 1128 1129 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, 1130 "could not check out %s", finfo->fullname); 1131 1132 retval = retcode; 1133 } 1134 1135 if (!pipeout) 1136 (void) unlink_file (backup); 1137 1138 return (retval); 1139 } 1140 1141 #ifdef SERVER_SUPPORT 1142 /* Patch a file. Runs rcsdiff. This is only done when running as the 1143 * server. The hope is that the diff will be smaller than the file 1144 * itself. 1145 */ 1146 static int 1147 patch_file (finfo, vers_ts, docheckout, file_info, checksum) 1148 struct file_info *finfo; 1149 Vers_TS *vers_ts; 1150 int *docheckout; 1151 struct stat *file_info; 1152 unsigned char *checksum; 1153 { 1154 char backup[PATH_MAX]; 1155 char file1[PATH_MAX]; 1156 char file2[PATH_MAX]; 1157 int retval = 0; 1158 int retcode = 0; 1159 int fail; 1160 long file_size; 1161 FILE *e; 1162 1163 *docheckout = 0; 1164 1165 if (pipeout || joining ()) 1166 { 1167 *docheckout = 1; 1168 return 0; 1169 } 1170 1171 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); 1172 if (isfile (finfo->file)) 1173 rename_file (finfo->file, backup); 1174 else 1175 (void) unlink_file (backup); 1176 1177 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file); 1178 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file); 1179 1180 fail = 0; 1181 1182 /* We need to check out both revisions first, to see if either one 1183 has a trailing newline. Because of this, we don't use rcsdiff, 1184 but just use diff. */ 1185 if (noexec) 1186 retcode = 0; 1187 else 1188 retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL, 1189 vers_ts->vn_user, (char *) NULL, 1190 vers_ts->options, file1); 1191 if (retcode != 0) 1192 fail = 1; 1193 else 1194 { 1195 e = CVS_FOPEN (file1, "r"); 1196 if (e == NULL) 1197 fail = 1; 1198 else 1199 { 1200 if (fseek (e, (long) -1, SEEK_END) == 0 1201 && getc (e) != '\n') 1202 { 1203 fail = 1; 1204 } 1205 fclose (e); 1206 } 1207 } 1208 1209 if (! fail) 1210 { 1211 /* Check it out into finfo->file, and then move to file2, so that we 1212 can get the right modes into *FILE_INFO. We can't check it 1213 out directly into file2 because co doesn't understand how 1214 to do that. */ 1215 retcode = RCS_checkout (vers_ts->srcfile, finfo->file, 1216 vers_ts->vn_rcs, (char *) NULL, 1217 vers_ts->options, RUN_TTY); 1218 if (retcode != 0) 1219 fail = 1; 1220 else 1221 { 1222 if (!isreadable (finfo->file)) 1223 { 1224 /* File is dead. */ 1225 fail = 1; 1226 } 1227 else 1228 { 1229 rename_file (finfo->file, file2); 1230 if (cvswrite == TRUE 1231 && !fileattr_get (finfo->file, "_watched")) 1232 xchmod (file2, 1); 1233 e = CVS_FOPEN (file2, "r"); 1234 if (e == NULL) 1235 fail = 1; 1236 else 1237 { 1238 struct MD5Context context; 1239 int nl; 1240 unsigned char buf[8192]; 1241 unsigned len; 1242 1243 nl = 0; 1244 1245 /* Compute the MD5 checksum and make sure there is 1246 a trailing newline. */ 1247 MD5Init (&context); 1248 while ((len = fread (buf, 1, sizeof buf, e)) != 0) 1249 { 1250 nl = buf[len - 1] == '\n'; 1251 MD5Update (&context, buf, len); 1252 } 1253 MD5Final (checksum, &context); 1254 1255 if (ferror (e) || ! nl) 1256 { 1257 fail = 1; 1258 } 1259 1260 fseek(e, 0L, SEEK_END); 1261 file_size = ftell(e); 1262 1263 fclose (e); 1264 } 1265 } 1266 } 1267 } 1268 1269 retcode = 0; 1270 if (! fail) 1271 { 1272 /* FIXME: This whole thing with diff/patch is rather more 1273 convoluted than necessary (lots of forks and execs, need to 1274 worry about versions of diff and patch, etc.). Also, we 1275 send context lines which aren't needed (in the rare case in 1276 which the diff doesn't apply, the checksum would catches it). 1277 Solution perhaps is to librarify the RCS routines which apply 1278 deltas or something equivalent. */ 1279 /* This is -c, not -u, because we have no way of knowing which 1280 DIFF is in use. */ 1281 run_setup ("%s -c %s %s", DIFF, file1, file2); 1282 1283 /* A retcode of 0 means no differences. 1 means some differences. */ 1284 if ((retcode = run_exec (RUN_TTY, finfo->file, RUN_TTY, RUN_NORMAL)) != 0 1285 && retcode != 1) 1286 { 1287 fail = 1; 1288 } 1289 else 1290 { 1291 #define BINARY "Binary" 1292 char buf[sizeof BINARY]; 1293 unsigned int c; 1294 1295 /* Check the diff output to make sure patch will be handle it. */ 1296 e = CVS_FOPEN (finfo->file, "r"); 1297 if (e == NULL) 1298 error (1, errno, "could not open diff output file %s", 1299 finfo->fullname); 1300 c = fread (buf, 1, sizeof BINARY - 1, e); 1301 buf[c] = '\0'; 1302 if (strcmp (buf, BINARY) == 0) 1303 { 1304 /* These are binary files. We could use diff -a, but 1305 patch can't handle that. */ 1306 fail = 1; 1307 } 1308 else { 1309 /* 1310 * Don't send a diff if just sending the entire file 1311 * would be smaller 1312 */ 1313 fseek(e, 0L, SEEK_END); 1314 if (file_size < ftell(e)) 1315 fail = 1; 1316 } 1317 1318 fclose (e); 1319 } 1320 } 1321 1322 if (! fail) 1323 { 1324 Vers_TS *xvers_ts; 1325 1326 /* This stuff is just copied blindly from checkout_file. I 1327 don't really know what it does. */ 1328 xvers_ts = Version_TS (finfo, options, tag, date, 1329 force_tag_match, 0); 1330 if (strcmp (xvers_ts->options, "-V4") == 0) 1331 xvers_ts->options[0] = '\0'; 1332 1333 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs, 1334 xvers_ts->ts_user, xvers_ts->options, 1335 xvers_ts->tag, xvers_ts->date, NULL); 1336 1337 if ( CVS_STAT (file2, file_info) < 0) 1338 error (1, errno, "could not stat %s", file2); 1339 1340 /* If this is really Update and not Checkout, recode history */ 1341 if (strcmp (command_name, "update") == 0) 1342 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, finfo->file, 1343 finfo->repository); 1344 1345 freevers_ts (&xvers_ts); 1346 1347 if (!really_quiet) 1348 { 1349 write_letter (finfo->file, 'P', finfo->update_dir); 1350 } 1351 } 1352 else 1353 { 1354 int old_errno = errno; /* save errno value over the rename */ 1355 1356 if (isfile (backup)) 1357 rename_file (backup, finfo->file); 1358 1359 if (retcode != 0 && retcode != 1) 1360 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, 1361 "could not diff %s", finfo->fullname); 1362 1363 *docheckout = 1; 1364 retval = retcode; 1365 } 1366 1367 (void) unlink_file (backup); 1368 (void) unlink_file (file1); 1369 (void) unlink_file (file2); 1370 1371 return (retval); 1372 } 1373 #endif 1374 1375 /* 1376 * Several of the types we process only print a bit of information consisting 1377 * of a single letter and the name. 1378 */ 1379 static int 1380 write_letter (file, letter, update_dir) 1381 char *file; 1382 int letter; 1383 char *update_dir; 1384 { 1385 if (!really_quiet) 1386 { 1387 char buf[2]; 1388 buf[0] = letter; 1389 buf[1] = ' '; 1390 cvs_output (buf, 2); 1391 if (update_dir[0]) 1392 { 1393 cvs_output (update_dir, 0); 1394 cvs_output ("/", 1); 1395 } 1396 cvs_output (file, 0); 1397 cvs_output ("\n", 1); 1398 } 1399 return (0); 1400 } 1401 1402 /* 1403 * Do all the magic associated with a file which needs to be merged 1404 */ 1405 static int 1406 merge_file (finfo, vers) 1407 struct file_info *finfo; 1408 Vers_TS *vers; 1409 { 1410 char backup[PATH_MAX]; 1411 int status; 1412 int retcode = 0; 1413 1414 /* 1415 * The users currently modified file is moved to a backup file name 1416 * ".#filename.version", so that it will stay around for a few days 1417 * before being automatically removed by some cron daemon. The "version" 1418 * is the version of the file that the user was most up-to-date with 1419 * before the merge. 1420 */ 1421 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); 1422 1423 (void) unlink_file (backup); 1424 copy_file (finfo->file, backup); 1425 xchmod (finfo->file, 1); 1426 1427 if (strcmp (vers->options, "-kb") == 0) 1428 { 1429 /* For binary files, a merge is always a conflict. We give the 1430 user the two files, and let them resolve it. It is possible 1431 that we should require a "touch foo" or similar step before 1432 we allow a checkin. */ 1433 status = checkout_file (finfo, vers, 0); 1434 #ifdef SERVER_SUPPORT 1435 /* Send the new contents of the file before the message. If we 1436 wanted to be totally correct, we would have the client write 1437 the message only after the file has safely been written. */ 1438 if (server_active) 1439 { 1440 server_copy_file (finfo->file, finfo->update_dir, 1441 finfo->repository, backup); 1442 server_updated (finfo, vers, SERVER_MERGED, 1443 (struct stat *) NULL, (unsigned char *) NULL); 1444 } 1445 #endif 1446 error (0, 0, "binary file needs merge"); 1447 error (0, 0, "revision %s from repository is now in %s", 1448 vers->vn_rcs, finfo->fullname); 1449 error (0, 0, "file from working directory is now in %s", backup); 1450 write_letter (finfo->file, 'C', finfo->update_dir); 1451 1452 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1453 return 0; 1454 } 1455 1456 status = RCS_merge(vers->srcfile->path, 1457 vers->options, vers->vn_user, vers->vn_rcs); 1458 if (status != 0 && status != 1) 1459 { 1460 error (0, status == -1 ? errno : 0, 1461 "could not merge revision %s of %s", vers->vn_user, finfo->fullname); 1462 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1463 finfo->fullname, backup); 1464 rename_file (backup, finfo->file); 1465 return (1); 1466 } 1467 1468 if (strcmp (vers->options, "-V4") == 0) 1469 vers->options[0] = '\0'; 1470 (void) time (&last_register_time); 1471 { 1472 char *cp = 0; 1473 1474 if (status) 1475 cp = time_stamp (finfo->file); 1476 Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, vers->options, 1477 vers->tag, vers->date, cp); 1478 if (cp) 1479 free (cp); 1480 } 1481 1482 /* fix up the vers structure, in case it is used by join */ 1483 if (join_rev1) 1484 { 1485 if (vers->vn_user != NULL) 1486 free (vers->vn_user); 1487 vers->vn_user = xstrdup (vers->vn_rcs); 1488 } 1489 1490 #ifdef SERVER_SUPPORT 1491 /* Send the new contents of the file before the message. If we 1492 wanted to be totally correct, we would have the client write 1493 the message only after the file has safely been written. */ 1494 if (server_active) 1495 { 1496 server_copy_file (finfo->file, finfo->update_dir, finfo->repository, 1497 backup); 1498 server_updated (finfo, vers, SERVER_MERGED, 1499 (struct stat *) NULL, (unsigned char *) NULL); 1500 } 1501 #endif 1502 1503 if (!noexec && !xcmp (backup, finfo->file)) 1504 { 1505 printf ("%s already contains the differences between %s and %s\n", 1506 finfo->fullname, vers->vn_user, vers->vn_rcs); 1507 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1508 return (0); 1509 } 1510 1511 if (status == 1) 1512 { 1513 if (!noexec) 1514 error (0, 0, "conflicts found in %s", finfo->fullname); 1515 1516 write_letter (finfo->file, 'C', finfo->update_dir); 1517 1518 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1519 1520 } 1521 else if (retcode == -1) 1522 { 1523 error (1, errno, "fork failed while examining update of %s", finfo->fullname); 1524 } 1525 else 1526 { 1527 write_letter (finfo->file, 'M', finfo->update_dir); 1528 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository); 1529 } 1530 return (0); 1531 } 1532 1533 /* 1534 * Do all the magic associated with a file which needs to be joined 1535 * (-j option) 1536 */ 1537 static void 1538 join_file (finfo, vers) 1539 struct file_info *finfo; 1540 Vers_TS *vers; 1541 { 1542 char backup[PATH_MAX]; 1543 char *options; 1544 int status; 1545 1546 char *rev1; 1547 char *rev2; 1548 char *jrev1; 1549 char *jrev2; 1550 char *jdate1; 1551 char *jdate2; 1552 1553 jrev1 = join_rev1; 1554 jrev2 = join_rev2; 1555 jdate1 = date_rev1; 1556 jdate2 = date_rev2; 1557 1558 if (wrap_merge_is_copy (finfo->file)) 1559 { 1560 error (0, 0, 1561 "Cannot merge %s because it is a merge-by-copy file.", 1562 finfo->fullname); 1563 return; 1564 } 1565 1566 /* Determine if we need to do anything at all. */ 1567 if (vers->srcfile == NULL || 1568 vers->srcfile->path == NULL) 1569 { 1570 return; 1571 } 1572 1573 /* If only one join revision is specified, it becomes the second 1574 revision. */ 1575 if (jrev2 == NULL) 1576 { 1577 jrev2 = jrev1; 1578 jrev1 = NULL; 1579 jdate2 = jdate1; 1580 jdate1 = NULL; 1581 } 1582 1583 /* Convert the second revision, walking branches and dates. */ 1584 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL); 1585 1586 /* If this is a merge of two revisions, get the first revision. 1587 If only one join tag was specified, then the first revision is 1588 the greatest common ancestor of the second revision and the 1589 working file. */ 1590 if (jrev1 != NULL) 1591 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL); 1592 else 1593 { 1594 /* Note that we use vn_rcs here, since vn_user may contain a 1595 special string such as "-nn". */ 1596 if (vers->vn_rcs == NULL) 1597 rev1 = NULL; 1598 else if (rev2 == NULL) 1599 { 1600 /* This means that the file never existed on the branch. 1601 It does not mean that the file was removed on the 1602 branch: that case is represented by a dead rev2. If 1603 the file never existed on the branch, then we have 1604 nothing to merge, so we just return. */ 1605 return; 1606 } 1607 else 1608 rev1 = gca (vers->vn_rcs, rev2); 1609 } 1610 1611 /* Handle a nonexistent or dead merge target. */ 1612 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2)) 1613 { 1614 char *mrev; 1615 1616 if (rev2 != NULL) 1617 free (rev2); 1618 1619 /* If the first revision doesn't exist either, then there is 1620 no change between the two revisions, so we don't do 1621 anything. */ 1622 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) 1623 { 1624 if (rev1 != NULL) 1625 free (rev1); 1626 return; 1627 } 1628 1629 /* If we are merging two revisions, then the file was removed 1630 between the first revision and the second one. In this 1631 case we want to mark the file for removal. 1632 1633 If we are merging one revision, then the file has been 1634 removed between the greatest common ancestor and the merge 1635 revision. From the perspective of the branch on to which 1636 we ar emerging, which may be the trunk, either 1) the file 1637 does not currently exist on the target, or 2) the file has 1638 not been modified on the target branch since the greatest 1639 common ancestor, or 3) the file has been modified on the 1640 target branch since the greatest common ancestor. In case 1641 1 there is nothing to do. In case 2 we mark the file for 1642 removal. In case 3 we have a conflict. 1643 1644 Note that the handling is slightly different depending upon 1645 whether one or two join targets were specified. If two 1646 join targets were specified, we don't check whether the 1647 file was modified since a given point. My reasoning is 1648 that if you ask for an explicit merge between two tags, 1649 then you want to merge in whatever was changed between 1650 those two tags. If a file was removed between the two 1651 tags, then you want it to be removed. However, if you ask 1652 for a merge of a branch, then you want to merge in all 1653 changes which were made on the branch. If a file was 1654 removed on the branch, that is a change to the file. If 1655 the file was also changed on the main line, then that is 1656 also a change. These two changes--the file removal and the 1657 modification--must be merged. This is a conflict. */ 1658 1659 /* If the user file is dead, or does not exist, or has been 1660 marked for removal, then there is nothing to do. */ 1661 if (vers->vn_user == NULL 1662 || vers->vn_user[0] == '-' 1663 || RCS_isdead (vers->srcfile, vers->vn_user)) 1664 { 1665 if (rev1 != NULL) 1666 free (rev1); 1667 return; 1668 } 1669 1670 /* If the user file has been marked for addition, or has been 1671 locally modified, then we have a conflict which we can not 1672 resolve. No_Difference will already have been called in 1673 this case, so comparing the timestamps is sufficient to 1674 determine whether the file is locally modified. */ 1675 if (strcmp (vers->vn_user, "0") == 0 1676 || (vers->ts_user != NULL 1677 && strcmp (vers->ts_user, vers->ts_rcs) != 0)) 1678 { 1679 if (jdate2 != NULL) 1680 error (0, 0, 1681 "file %s is locally modified, but has been removed in revision %s as of %s", 1682 finfo->fullname, jrev2, jdate2); 1683 else 1684 error (0, 0, 1685 "file %s is locally modified, but has been removed in revision %s", 1686 finfo->fullname, jrev2); 1687 1688 /* FIXME: Should we arrange to return a non-zero exit 1689 status? */ 1690 1691 if (rev1 != NULL) 1692 free (rev1); 1693 1694 return; 1695 } 1696 1697 /* If only one join tag was specified, and the user file has 1698 been changed since the greatest common ancestor (rev1), 1699 then there is a conflict we can not resolve. See above for 1700 the rationale. */ 1701 if (join_rev2 == NULL 1702 && strcmp (rev1, vers->vn_user) != 0) 1703 { 1704 if (jdate2 != NULL) 1705 error (0, 0, 1706 "file %s has been modified, but has been removed in revision %s as of %s", 1707 finfo->fullname, jrev2, jdate2); 1708 else 1709 error (0, 0, 1710 "file %s has been modified, but has been removed in revision %s", 1711 finfo->fullname, jrev2); 1712 1713 /* FIXME: Should we arrange to return a non-zero exit 1714 status? */ 1715 1716 if (rev1 != NULL) 1717 free (rev1); 1718 1719 return; 1720 } 1721 1722 if (rev1 != NULL) 1723 free (rev1); 1724 1725 /* The user file exists and has not been modified. Mark it 1726 for removal. FIXME: If we are doing a checkout, this has 1727 the effect of first checking out the file, and then 1728 removing it. It would be better to just register the 1729 removal. */ 1730 #ifdef SERVER_SUPPORT 1731 if (server_active) 1732 { 1733 server_scratch (finfo->file); 1734 server_updated (finfo, vers, SERVER_UPDATED, (struct stat *) NULL, 1735 (unsigned char *) NULL); 1736 } 1737 #endif 1738 mrev = xmalloc (strlen (vers->vn_user) + 2); 1739 sprintf (mrev, "-%s", vers->vn_user); 1740 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs, 1741 vers->options, vers->tag, vers->date, vers->ts_conflict); 1742 free (mrev); 1743 /* We need to check existence_error here because if we are 1744 running as the server, and the file is up to date in the 1745 working directory, the client will not have sent us a copy. */ 1746 if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) 1747 error (0, errno, "cannot remove file %s", finfo->fullname); 1748 #ifdef SERVER_SUPPORT 1749 if (server_active) 1750 server_checked_in (finfo->file, finfo->update_dir, 1751 finfo->repository); 1752 #endif 1753 if (! really_quiet) 1754 error (0, 0, "scheduling %s for removal", finfo->fullname); 1755 1756 return; 1757 } 1758 1759 /* If the target of the merge is the same as the working file 1760 revision, then there is nothing to do. */ 1761 if (vers->vn_user != NULL && strcmp (rev2, vers->vn_user) == 0) 1762 { 1763 if (rev1 != NULL) 1764 free (rev1); 1765 free (rev2); 1766 return; 1767 } 1768 1769 /* If rev1 is dead or does not exist, then the file was added 1770 between rev1 and rev2. */ 1771 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) 1772 { 1773 if (rev1 != NULL) 1774 free (rev1); 1775 free (rev2); 1776 1777 /* If the file does not exist in the working directory, then 1778 we can just check out the new revision and mark it for 1779 addition. */ 1780 if (vers->vn_user == NULL) 1781 { 1782 Vers_TS *xvers; 1783 1784 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); 1785 1786 /* FIXME: If checkout_file fails, we should arrange to 1787 return a non-zero exit status. */ 1788 status = checkout_file (finfo, xvers, 1); 1789 1790 #ifdef SERVER_SUPPORT 1791 if (server_active && status == 0) 1792 server_updated (finfo, xvers, 1793 SERVER_UPDATED, (struct stat *) NULL, 1794 (unsigned char *) NULL); 1795 #endif 1796 1797 freevers_ts (&xvers); 1798 1799 return; 1800 } 1801 1802 /* The file currently exists in the working directory, so we 1803 have a conflict which we can not resolve. Note that this 1804 is true even if the file is marked for addition or removal. */ 1805 1806 if (jdate2 != NULL) 1807 error (0, 0, 1808 "file %s exists, but has been added in revision %s as of %s", 1809 finfo->fullname, jrev2, jdate2); 1810 else 1811 error (0, 0, 1812 "file %s exists, but has been added in revision %s", 1813 finfo->fullname, jrev2); 1814 1815 return; 1816 } 1817 1818 /* If the two merge revisions are the same, then there is nothing 1819 to do. */ 1820 if (strcmp (rev1, rev2) == 0) 1821 { 1822 free (rev1); 1823 free (rev2); 1824 return; 1825 } 1826 1827 /* If there is no working file, then we can't do the merge. */ 1828 if (vers->vn_user == NULL) 1829 { 1830 free (rev1); 1831 free (rev2); 1832 1833 if (jdate2 != NULL) 1834 error (0, 0, 1835 "file %s is present in revision %s as of %s", 1836 finfo->fullname, jrev2, jdate2); 1837 else 1838 error (0, 0, 1839 "file %s is present in revision %s", 1840 finfo->fullname, jrev2); 1841 1842 /* FIXME: Should we arrange to return a non-zero exit status? */ 1843 1844 return; 1845 } 1846 1847 #ifdef SERVER_SUPPORT 1848 if (server_active && !isreadable (finfo->file)) 1849 { 1850 int retcode; 1851 /* The file is up to date. Need to check out the current contents. */ 1852 retcode = RCS_checkout (vers->srcfile, finfo->file, 1853 vers->vn_user, (char *) NULL, 1854 (char *) NULL, RUN_TTY); 1855 if (retcode != 0) 1856 error (1, retcode == -1 ? errno : 0, 1857 "failed to check out %s file", finfo->fullname); 1858 } 1859 #endif 1860 1861 /* 1862 * The users currently modified file is moved to a backup file name 1863 * ".#filename.version", so that it will stay around for a few days 1864 * before being automatically removed by some cron daemon. The "version" 1865 * is the version of the file that the user was most up-to-date with 1866 * before the merge. 1867 */ 1868 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); 1869 1870 (void) unlink_file (backup); 1871 copy_file (finfo->file, backup); 1872 xchmod (finfo->file, 1); 1873 1874 options = vers->options; 1875 #ifdef HAVE_RCS5 1876 #if 0 1877 if (*options == '\0') 1878 options = "-kk"; /* to ignore keyword expansions */ 1879 #endif 1880 #endif 1881 1882 status = RCS_merge (vers->srcfile->path, options, rev1, rev2); 1883 if (status != 0 && status != 1) 1884 { 1885 error (0, status == -1 ? errno : 0, 1886 "could not merge revision %s of %s", rev2, finfo->fullname); 1887 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1888 finfo->fullname, backup); 1889 rename_file (backup, finfo->file); 1890 } 1891 free (rev1); 1892 free (rev2); 1893 1894 #ifdef SERVER_SUPPORT 1895 /* 1896 * If we're in server mode, then we need to re-register the file 1897 * even if there were no conflicts (status == 0). 1898 * This tells server_updated() to send the modified file back to 1899 * the client. 1900 */ 1901 if (status == 1 || (status == 0 && server_active)) 1902 #else 1903 if (status == 1) 1904 #endif 1905 { 1906 char *cp = 0; 1907 1908 if (status) 1909 cp = time_stamp (finfo->file); 1910 Register (finfo->entries, finfo->file, 1911 vers->vn_rcs, vers->ts_rcs, vers->options, 1912 vers->tag, vers->date, cp); 1913 if (cp) 1914 free(cp); 1915 } 1916 1917 #ifdef SERVER_SUPPORT 1918 if (server_active) 1919 { 1920 server_copy_file (finfo->file, finfo->update_dir, finfo->repository, 1921 backup); 1922 server_updated (finfo, vers, SERVER_MERGED, 1923 (struct stat *) NULL, (unsigned char *) NULL); 1924 } 1925 #endif 1926 } 1927 1928 int 1929 joining () 1930 { 1931 return (join_rev1 != NULL); 1932 } 1933