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