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