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