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 FILE *e; 1164 1165 *docheckout = 0; 1166 1167 if (pipeout || joining ()) 1168 { 1169 *docheckout = 1; 1170 return 0; 1171 } 1172 1173 (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file); 1174 if (isfile (file)) 1175 rename_file (file, backup); 1176 else 1177 (void) unlink_file (backup); 1178 1179 (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, file); 1180 (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, file); 1181 1182 fail = 0; 1183 1184 /* We need to check out both revisions first, to see if either one 1185 has a trailing newline. Because of this, we don't use rcsdiff, 1186 but just use diff. */ 1187 if (noexec) 1188 retcode = 0; 1189 else 1190 retcode = RCS_checkout (vers_ts->srcfile->path, NULL, 1191 vers_ts->vn_user, 1192 vers_ts->options, file1, 0, 0); 1193 if (retcode != 0) 1194 fail = 1; 1195 else 1196 { 1197 e = fopen (file1, "r"); 1198 if (e == NULL) 1199 fail = 1; 1200 else 1201 { 1202 if (fseek (e, (long) -1, SEEK_END) == 0 1203 && getc (e) != '\n') 1204 { 1205 fail = 1; 1206 } 1207 fclose (e); 1208 } 1209 } 1210 1211 if (! fail) 1212 { 1213 /* Check it out into file, and then move to file2, so that we 1214 can get the right modes into *FILE_INFO. We can't check it 1215 out directly into file2 because co doesn't understand how 1216 to do that. */ 1217 retcode = RCS_checkout (vers_ts->srcfile->path, file, 1218 vers_ts->vn_rcs, 1219 vers_ts->options, RUN_TTY, 0, 0); 1220 if (retcode != 0) 1221 fail = 1; 1222 else 1223 { 1224 if (!isreadable (file)) 1225 { 1226 /* File is dead. */ 1227 fail = 1; 1228 } 1229 else 1230 { 1231 rename_file (file, file2); 1232 if (cvswrite == TRUE 1233 && !fileattr_get (file, "_watched")) 1234 xchmod (file2, 1); 1235 e = fopen (file2, "r"); 1236 if (e == NULL) 1237 fail = 1; 1238 else 1239 { 1240 struct MD5Context context; 1241 int nl; 1242 unsigned char buf[8192]; 1243 unsigned len; 1244 1245 nl = 0; 1246 1247 /* Compute the MD5 checksum and make sure there is 1248 a trailing newline. */ 1249 MD5Init (&context); 1250 while ((len = fread (buf, 1, sizeof buf, e)) != 0) 1251 { 1252 nl = buf[len - 1] == '\n'; 1253 MD5Update (&context, buf, len); 1254 } 1255 MD5Final (checksum, &context); 1256 1257 if (ferror (e) || ! nl) 1258 { 1259 fail = 1; 1260 } 1261 1262 fclose (e); 1263 } 1264 } 1265 } 1266 } 1267 1268 retcode = 0; 1269 if (! fail) 1270 { 1271 /* FIXME: This whole thing with diff/patch is rather more 1272 convoluted than necessary (lots of forks and execs, need to 1273 worry about versions of diff and patch, etc.). Also, we 1274 send context lines which aren't needed (in the rare case in 1275 which the diff doesn't apply, the checksum would catches it). 1276 Solution perhaps is to librarify the RCS routines which apply 1277 deltas or something equivalent. */ 1278 /* This is -c, not -u, because we have no way of knowing which 1279 DIFF is in use. */ 1280 run_setup ("%s -c %s %s", DIFF, file1, file2); 1281 1282 /* A retcode of 0 means no differences. 1 means some differences. */ 1283 if ((retcode = run_exec (RUN_TTY, file, RUN_TTY, RUN_NORMAL)) != 0 1284 && retcode != 1) 1285 { 1286 fail = 1; 1287 } 1288 else 1289 { 1290 #define BINARY "Binary" 1291 char buf[sizeof BINARY]; 1292 unsigned int c; 1293 1294 /* Check the diff output to make sure patch will be handle it. */ 1295 e = fopen (file, "r"); 1296 if (e == NULL) 1297 error (1, errno, "could not open diff output file %s", file); 1298 c = fread (buf, 1, sizeof BINARY - 1, e); 1299 buf[c] = '\0'; 1300 if (strcmp (buf, BINARY) == 0) 1301 { 1302 /* These are binary files. We could use diff -a, but 1303 patch can't handle that. */ 1304 fail = 1; 1305 } 1306 fclose (e); 1307 } 1308 } 1309 1310 if (! fail) 1311 { 1312 Vers_TS *xvers_ts; 1313 1314 /* This stuff is just copied blindly from checkout_file. I 1315 don't really know what it does. */ 1316 xvers_ts = Version_TS (repository, options, tag, date, file, 1317 force_tag_match, 0, entries, srcfiles); 1318 if (strcmp (xvers_ts->options, "-V4") == 0) 1319 xvers_ts->options[0] = '\0'; 1320 1321 Register (entries, file, xvers_ts->vn_rcs, 1322 xvers_ts->ts_user, xvers_ts->options, 1323 xvers_ts->tag, xvers_ts->date, NULL); 1324 1325 if (stat (file2, file_info) < 0) 1326 error (1, errno, "could not stat %s", file2); 1327 1328 /* If this is really Update and not Checkout, recode history */ 1329 if (strcmp (command_name, "update") == 0) 1330 history_write ('P', update_dir, xvers_ts->vn_rcs, file, 1331 repository); 1332 1333 freevers_ts (&xvers_ts); 1334 1335 if (!really_quiet) 1336 { 1337 write_letter (file, 'P', update_dir); 1338 } 1339 } 1340 else 1341 { 1342 int old_errno = errno; /* save errno value over the rename */ 1343 1344 if (isfile (backup)) 1345 rename_file (backup, file); 1346 1347 if (retcode != 0 && retcode != 1) 1348 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, 1349 "could not diff %s", file); 1350 1351 *docheckout = 1; 1352 retval = retcode; 1353 } 1354 1355 (void) unlink_file (backup); 1356 (void) unlink_file (file1); 1357 (void) unlink_file (file2); 1358 1359 return (retval); 1360 } 1361 #endif 1362 1363 /* 1364 * Several of the types we process only print a bit of information consisting 1365 * of a single letter and the name. 1366 */ 1367 static int 1368 write_letter (file, letter, update_dir) 1369 char *file; 1370 int letter; 1371 char *update_dir; 1372 { 1373 if (!really_quiet) 1374 { 1375 char buf[2]; 1376 buf[0] = letter; 1377 buf[1] = ' '; 1378 cvs_output (buf, 2); 1379 if (update_dir[0]) 1380 { 1381 cvs_output (update_dir, 0); 1382 cvs_output ("/", 1); 1383 } 1384 cvs_output (file, 0); 1385 cvs_output ("\n", 1); 1386 } 1387 return (0); 1388 } 1389 1390 /* 1391 * Do all the magic associated with a file which needs to be merged 1392 */ 1393 static int 1394 merge_file (file, repository, entries, vers, update_dir) 1395 char *file; 1396 char *repository; 1397 List *entries; 1398 Vers_TS *vers; 1399 char *update_dir; 1400 { 1401 char user[PATH_MAX]; 1402 char backup[PATH_MAX]; 1403 int status; 1404 int retcode = 0; 1405 1406 /* 1407 * The users currently modified file is moved to a backup file name 1408 * ".#filename.version", so that it will stay around for a few days 1409 * before being automatically removed by some cron daemon. The "version" 1410 * is the version of the file that the user was most up-to-date with 1411 * before the merge. 1412 */ 1413 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user); 1414 if (update_dir[0]) 1415 (void) sprintf (user, "%s/%s", update_dir, file); 1416 else 1417 (void) strcpy (user, file); 1418 1419 (void) unlink_file (backup); 1420 copy_file (file, backup); 1421 xchmod (file, 1); 1422 1423 status = RCS_merge(vers->srcfile->path, 1424 vers->options, vers->vn_user, vers->vn_rcs); 1425 if (status != 0 && status != 1) 1426 { 1427 error (0, status == -1 ? errno : 0, 1428 "could not merge revision %s of %s", vers->vn_user, user); 1429 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1430 user, backup); 1431 rename_file (backup, file); 1432 return (1); 1433 } 1434 1435 if (strcmp (vers->options, "-V4") == 0) 1436 vers->options[0] = '\0'; 1437 (void) time (&last_register_time); 1438 { 1439 char *cp = 0; 1440 1441 if (status) 1442 cp = time_stamp (file); 1443 Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options, 1444 vers->tag, vers->date, cp); 1445 if (cp) 1446 free (cp); 1447 } 1448 1449 /* fix up the vers structure, in case it is used by join */ 1450 if (join_rev1) 1451 { 1452 if (vers->vn_user != NULL) 1453 free (vers->vn_user); 1454 vers->vn_user = xstrdup (vers->vn_rcs); 1455 } 1456 1457 #ifdef SERVER_SUPPORT 1458 /* Send the new contents of the file before the message. If we 1459 wanted to be totally correct, we would have the client write 1460 the message only after the file has safely been written. */ 1461 if (server_active) 1462 { 1463 server_copy_file (file, update_dir, repository, backup); 1464 server_updated (file, update_dir, repository, SERVER_MERGED, 1465 (struct stat *) NULL, (unsigned char *) NULL); 1466 } 1467 #endif 1468 1469 if (!noexec && !xcmp (backup, file)) 1470 { 1471 printf ("%s already contains the differences between %s and %s\n", 1472 user, vers->vn_user, vers->vn_rcs); 1473 history_write ('G', update_dir, vers->vn_rcs, file, repository); 1474 return (0); 1475 } 1476 1477 if (status == 1) 1478 { 1479 if (!noexec) 1480 error (0, 0, "conflicts found in %s", user); 1481 1482 write_letter (file, 'C', update_dir); 1483 1484 history_write ('C', update_dir, vers->vn_rcs, file, repository); 1485 1486 } 1487 else if (retcode == -1) 1488 { 1489 error (1, errno, "fork failed while examining update of %s", user); 1490 } 1491 else 1492 { 1493 write_letter (file, 'M', update_dir); 1494 history_write ('G', update_dir, vers->vn_rcs, file, repository); 1495 } 1496 return (0); 1497 } 1498 1499 /* 1500 * Do all the magic associated with a file which needs to be joined 1501 * (-j option) 1502 */ 1503 static void 1504 #ifdef SERVER_SUPPORT 1505 join_file (file, srcfiles, vers, update_dir, entries, repository) 1506 char *repository; 1507 #else 1508 join_file (file, srcfiles, vers, update_dir, entries) 1509 #endif 1510 char *file; 1511 List *srcfiles; 1512 Vers_TS *vers; 1513 char *update_dir; 1514 List *entries; 1515 { 1516 char user[PATH_MAX]; 1517 char backup[PATH_MAX]; 1518 char *options; 1519 int status; 1520 1521 char *rev1; 1522 char *rev2; 1523 char *jrev1; 1524 char *jrev2; 1525 char *jdate1; 1526 char *jdate2; 1527 1528 jrev1 = join_rev1; 1529 jrev2 = join_rev2; 1530 jdate1 = date_rev1; 1531 jdate2 = date_rev2; 1532 1533 if (wrap_merge_is_copy (file)) 1534 { 1535 /* FIXME: Should be including update_dir in message. */ 1536 error (0, 0, 1537 "Cannot merge %s because it is a merge-by-copy file.", file); 1538 return; 1539 } 1540 1541 /* determine if we need to do anything at all */ 1542 if (vers->srcfile == NULL || 1543 vers->srcfile->path == NULL) 1544 { 1545 return; 1546 } 1547 1548 /* in all cases, use two revs. */ 1549 1550 /* if only one rev is specified, it becomes the second rev */ 1551 if (jrev2 == NULL) 1552 { 1553 jrev2 = jrev1; 1554 jrev1 = NULL; 1555 jdate2 = jdate1; 1556 jdate1 = NULL; 1557 } 1558 1559 /* The file in the working directory doesn't exist in CVS/Entries. 1560 FIXME: Shouldn't this case result in additional processing (if 1561 the file was added going from rev1 to rev2, then do the equivalent 1562 of a "cvs add")? (yes; easier said than done.. :-) */ 1563 if (vers->vn_user == NULL) 1564 { 1565 /* No merge possible YET. */ 1566 if (jdate2 != NULL) 1567 error (0, 0, 1568 "file %s is present in revision %s as of %s", 1569 file, jrev2, jdate2); 1570 else 1571 error (0, 0, 1572 "file %s is present in revision %s", 1573 file, jrev2); 1574 return; 1575 } 1576 1577 /* Fix for bug CVS/193: 1578 * Used to dump core if the file had been removed on the current branch. 1579 */ 1580 if (strcmp(vers->vn_user, "0") == 0) 1581 { 1582 error(0, 0, 1583 "file %s has been deleted", 1584 file); 1585 return; 1586 } 1587 1588 /* convert the second rev spec, walking branches and dates. */ 1589 1590 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, 0); 1591 if (rev2 == NULL) 1592 { 1593 if (!quiet) 1594 { 1595 if (jdate2 != NULL) 1596 error (0, 0, 1597 "cannot find revision %s as of %s in file %s", 1598 jrev2, jdate2, file); 1599 else 1600 error (0, 0, 1601 "cannot find revision %s in file %s", 1602 jrev2, file); 1603 } 1604 return; 1605 } 1606 1607 /* skip joining identical revs */ 1608 if (strcmp (rev2, vers->vn_user) == 0) 1609 { 1610 /* No merge necessary. */ 1611 free (rev2); 1612 return; 1613 } 1614 1615 if (jrev1 == NULL) 1616 { 1617 char *tst; 1618 /* if the first rev is missing, then it is implied to be the 1619 greatest common ancestor of both the join rev, and the 1620 checked out rev. */ 1621 1622 /* FIXME: What is this check for '!' about? If it is legal to 1623 have '!' in the first character of vn_user, it isn't 1624 documented at struct vers_ts in cvs.h. */ 1625 tst = vers->vn_user; 1626 if (*tst == '!') 1627 { 1628 /* file was dead. merge anyway and pretend it's been 1629 added. */ 1630 ++tst; 1631 Register (entries, file, "0", vers->ts_user, vers->options, 1632 vers->tag, (char *) 0, (char *) 0); 1633 } 1634 rev1 = gca (tst, rev2); 1635 if (rev1 == NULL) 1636 { 1637 /* this should not be possible */ 1638 error (0, 0, "bad gca"); 1639 abort(); 1640 } 1641 1642 tst = RCS_gettag (vers->srcfile, rev2, 1, 0); 1643 if (tst == NULL) 1644 { 1645 /* this should not be possible. */ 1646 error (0, 0, "cannot find gca"); 1647 abort(); 1648 } 1649 1650 free (tst); 1651 1652 /* these two cases are noops */ 1653 if (strcmp (rev1, rev2) == 0) 1654 { 1655 free (rev1); 1656 free (rev2); 1657 return; 1658 } 1659 } 1660 else 1661 { 1662 /* otherwise, convert the first rev spec, walking branches and 1663 dates. */ 1664 1665 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, 0); 1666 if (rev1 == NULL) 1667 { 1668 if (!quiet) { 1669 if (jdate1 != NULL) 1670 error (0, 0, 1671 "cannot find revision %s as of %s in file %s", 1672 jrev1, jdate1, file); 1673 else 1674 error (0, 0, 1675 "cannot find revision %s in file %s", 1676 jrev1, file); 1677 } 1678 return; 1679 } 1680 } 1681 1682 /* do the join */ 1683 1684 #if 0 1685 dome { 1686 /* special handling when two revisions are specified */ 1687 if (join_rev1 && join_rev2) 1688 { 1689 rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1, 0); 1690 if (rev == NULL) 1691 { 1692 if (!quiet && date_rev2 == NULL) 1693 error (0, 0, 1694 "cannot find revision %s in file %s", join_rev2, file); 1695 return; 1696 } 1697 1698 baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0); 1699 if (baserev == NULL) 1700 { 1701 if (!quiet && date_rev1 == NULL) 1702 error (0, 0, 1703 "cannot find revision %s in file %s", join_rev1, file); 1704 free (rev); 1705 return; 1706 } 1707 1708 /* 1709 * nothing to do if: 1710 * second revision matches our BASE revision (vn_user) && 1711 * both revisions are on the same branch 1712 */ 1713 if (strcmp (vers->vn_user, rev) == 0 && 1714 numdots (baserev) == numdots (rev)) 1715 { 1716 /* might be the same branch. take a real look */ 1717 char *dot = strrchr (baserev, '.'); 1718 int len = (dot - baserev) + 1; 1719 1720 if (strncmp (baserev, rev, len) == 0) 1721 return; 1722 } 1723 } 1724 else 1725 { 1726 rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0); 1727 if (rev == NULL) 1728 return; 1729 if (strcmp (rev, vers->vn_user) == 0) /* no merge necessary */ 1730 { 1731 free (rev); 1732 return; 1733 } 1734 1735 baserev = RCS_whatbranch (file, join_rev1, srcfiles); 1736 if (baserev) 1737 { 1738 char *cp; 1739 1740 /* we get a branch -- turn it into a revision, or NULL if trunk */ 1741 if ((cp = strrchr (baserev, '.')) == NULL) 1742 { 1743 free (baserev); 1744 baserev = (char *) NULL; 1745 } 1746 else 1747 *cp = '\0'; 1748 } 1749 } 1750 if (baserev && strcmp (baserev, rev) == 0) 1751 { 1752 /* they match -> nothing to do */ 1753 free (rev); 1754 free (baserev); 1755 return; 1756 } 1757 } 1758 #endif 1759 1760 /* OK, so we have two revisions; continue on */ 1761 1762 #ifdef SERVER_SUPPORT 1763 if (server_active && !isreadable (file)) 1764 { 1765 int retcode; 1766 /* The file is up to date. Need to check out the current contents. */ 1767 retcode = RCS_checkout (vers->srcfile->path, "", vers->vn_user, NULL, 1768 RUN_TTY, 0, 0); 1769 if (retcode != 0) 1770 error (1, retcode == -1 ? errno : 0, 1771 "failed to check out %s file", file); 1772 } 1773 #endif 1774 1775 /* 1776 * The users currently modified file is moved to a backup file name 1777 * ".#filename.version", so that it will stay around for a few days 1778 * before being automatically removed by some cron daemon. The "version" 1779 * is the version of the file that the user was most up-to-date with 1780 * before the merge. 1781 */ 1782 (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user); 1783 if (update_dir[0]) 1784 (void) sprintf (user, "%s/%s", update_dir, file); 1785 else 1786 (void) strcpy (user, file); 1787 1788 (void) unlink_file (backup); 1789 copy_file (file, backup); 1790 xchmod (file, 1); 1791 1792 options = vers->options; 1793 #ifdef HAVE_RCS5 1794 #if 0 1795 if (*options == '\0') 1796 options = "-kk"; /* to ignore keyword expansions */ 1797 #endif 1798 #endif 1799 1800 status = RCS_merge (vers->srcfile->path, options, rev1, rev2); 1801 if (status != 0 && status != 1) 1802 { 1803 error (0, status == -1 ? errno : 0, 1804 "could not merge revision %s of %s", rev2, user); 1805 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", 1806 user, backup); 1807 rename_file (backup, file); 1808 } 1809 free (rev1); 1810 free (rev2); 1811 1812 #ifdef SERVER_SUPPORT 1813 /* 1814 * If we're in server mode, then we need to re-register the file 1815 * even if there were no conflicts (status == 0). 1816 * This tells server_updated() to send the modified file back to 1817 * the client. 1818 */ 1819 if (status == 1 || (status == 0 && server_active)) 1820 #else 1821 if (status == 1) 1822 #endif 1823 { 1824 char *cp = 0; 1825 1826 if (status) 1827 cp = time_stamp (file); 1828 Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options, 1829 vers->tag, vers->date, cp); 1830 if (cp) 1831 free(cp); 1832 } 1833 1834 #ifdef SERVER_SUPPORT 1835 if (server_active) 1836 { 1837 server_copy_file (file, update_dir, repository, backup); 1838 server_updated (file, update_dir, repository, SERVER_MERGED, 1839 (struct stat *) NULL, (unsigned char *) NULL); 1840 } 1841 #endif 1842 } 1843 1844 int 1845 joining () 1846 { 1847 return (join_rev1 != NULL); 1848 } 1849