1 /* $OpenBSD: update.c,v 1.167 2012/07/02 21:56:25 tedu Exp $ */ 2 /* 3 * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/stat.h> 19 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "cvs.h" 26 #include "diff.h" 27 #include "remote.h" 28 29 int prune_dirs = 0; 30 int print_stdout = 0; 31 int build_dirs = 0; 32 int reset_option = 0; 33 int reset_tag = 0; 34 int backup_local_changes = 0; 35 char *cvs_specified_tag = NULL; 36 char *cvs_join_rev1 = NULL; 37 char *cvs_join_rev2 = NULL; 38 39 static char *koptstr; 40 static char *dateflag = NULL; 41 static int Aflag = 0; 42 43 static void update_clear_conflict(struct cvs_file *); 44 static void update_join_file(struct cvs_file *); 45 46 extern CVSENTRIES *current_list; 47 48 struct cvs_cmd cvs_cmd_update = { 49 CVS_OP_UPDATE, CVS_USE_WDIR, "update", 50 { "up", "upd" }, 51 "Bring work tree in sync with repository", 52 "[-ACdflPpR] [-D date | -r rev] [-I ign] [-j rev] [-k mode] " 53 "[-t id] ...", 54 "ACD:dfI:j:k:lPpQqRr:t:u", 55 NULL, 56 cvs_update 57 }; 58 59 int 60 cvs_update(int argc, char **argv) 61 { 62 int ch; 63 char *arg = "."; 64 int flags; 65 struct cvs_recursion cr; 66 67 flags = CR_RECURSE_DIRS; 68 69 while ((ch = getopt(argc, argv, cvs_cmd_update.cmd_opts)) != -1) { 70 switch (ch) { 71 case 'A': 72 Aflag = 1; 73 if (koptstr == NULL) 74 reset_option = 1; 75 if (cvs_specified_tag == NULL) 76 reset_tag = 1; 77 break; 78 case 'C': 79 backup_local_changes = 1; 80 break; 81 case 'D': 82 dateflag = optarg; 83 if ((cvs_specified_date = date_parse(dateflag)) == -1) 84 fatal("invalid date: %s", dateflag); 85 reset_tag = 0; 86 break; 87 case 'd': 88 build_dirs = 1; 89 break; 90 case 'f': 91 break; 92 case 'I': 93 break; 94 case 'j': 95 if (cvs_join_rev1 == NULL) 96 cvs_join_rev1 = optarg; 97 else if (cvs_join_rev2 == NULL) 98 cvs_join_rev2 = optarg; 99 else 100 fatal("too many -j options"); 101 break; 102 case 'k': 103 reset_option = 0; 104 koptstr = optarg; 105 kflag = rcs_kflag_get(koptstr); 106 if (RCS_KWEXP_INVAL(kflag)) { 107 cvs_log(LP_ERR, 108 "invalid RCS keyword expansion mode"); 109 fatal("%s", cvs_cmd_update.cmd_synopsis); 110 } 111 break; 112 case 'l': 113 flags &= ~CR_RECURSE_DIRS; 114 break; 115 case 'P': 116 prune_dirs = 1; 117 break; 118 case 'p': 119 print_stdout = 1; 120 cvs_noexec = 1; 121 break; 122 case 'Q': 123 case 'q': 124 break; 125 case 'R': 126 flags |= CR_RECURSE_DIRS; 127 break; 128 case 'r': 129 reset_tag = 0; 130 cvs_specified_tag = optarg; 131 break; 132 case 'u': 133 break; 134 default: 135 fatal("%s", cvs_cmd_update.cmd_synopsis); 136 } 137 } 138 139 argc -= optind; 140 argv += optind; 141 142 if (current_cvsroot->cr_method == CVS_METHOD_LOCAL) { 143 cr.enterdir = cvs_update_enterdir; 144 cr.leavedir = prune_dirs ? cvs_update_leavedir : NULL; 145 cr.fileproc = cvs_update_local; 146 flags |= CR_REPO; 147 } else { 148 cvs_client_connect_to_server(); 149 if (Aflag) 150 cvs_client_send_request("Argument -A"); 151 if (dateflag != NULL) 152 cvs_client_send_request("Argument -D%s", dateflag); 153 if (build_dirs) 154 cvs_client_send_request("Argument -d"); 155 if (kflag) 156 cvs_client_send_request("Argument -k%s", koptstr); 157 if (!(flags & CR_RECURSE_DIRS)) 158 cvs_client_send_request("Argument -l"); 159 if (prune_dirs) 160 cvs_client_send_request("Argument -P"); 161 if (print_stdout) 162 cvs_client_send_request("Argument -p"); 163 164 if (cvs_specified_tag != NULL) 165 cvs_client_send_request("Argument -r%s", 166 cvs_specified_tag); 167 168 cr.enterdir = NULL; 169 cr.leavedir = NULL; 170 cr.fileproc = cvs_client_sendfile; 171 } 172 173 cr.flags = flags; 174 175 if (argc > 0) 176 cvs_file_run(argc, argv, &cr); 177 else 178 cvs_file_run(1, &arg, &cr); 179 180 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 181 cvs_client_send_files(argv, argc); 182 cvs_client_senddir("."); 183 cvs_client_send_request("update"); 184 cvs_client_get_responses(); 185 } 186 187 return (0); 188 } 189 190 void 191 cvs_update_enterdir(struct cvs_file *cf) 192 { 193 CVSENTRIES *entlist; 194 char *dirtag, *entry, fpath[MAXPATHLEN]; 195 196 cvs_log(LP_TRACE, "cvs_update_enterdir(%s)", cf->file_path); 197 198 cvs_file_classify(cf, NULL); 199 200 if (cf->file_status == DIR_CREATE && build_dirs == 1) { 201 cvs_parse_tagfile(cf->file_wd, &dirtag, NULL, NULL); 202 cvs_mkpath(cf->file_path, cvs_specified_tag != NULL ? 203 cvs_specified_tag : dirtag); 204 if (dirtag != NULL) 205 xfree(dirtag); 206 207 if ((cf->fd = open(cf->file_path, O_RDONLY)) == -1) 208 fatal("cvs_update_enterdir: `%s': %s", 209 cf->file_path, strerror(errno)); 210 211 if (cvs_server_active == 1 && cvs_cmdop != CVS_OP_CHECKOUT) 212 cvs_server_clear_sticky(cf->file_path); 213 214 if (cvs_cmdop != CVS_OP_EXPORT) { 215 (void)xasprintf(&entry, "D/%s////", cf->file_name); 216 217 entlist = cvs_ent_open(cf->file_wd); 218 cvs_ent_add(entlist, entry); 219 xfree(entry); 220 } 221 } else if ((cf->file_status == DIR_CREATE && build_dirs == 0) || 222 cf->file_status == FILE_UNKNOWN) { 223 cf->file_status = FILE_SKIP; 224 } else if (reset_tag) { 225 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", 226 cf->file_path, CVS_PATH_TAG); 227 (void)unlink(fpath); 228 } else { 229 if (cvs_specified_tag != NULL || cvs_specified_date != -1) 230 cvs_write_tagfile(cf->file_path, 231 cvs_specified_tag, NULL); 232 } 233 } 234 235 void 236 cvs_update_leavedir(struct cvs_file *cf) 237 { 238 off_t base; 239 int nbytes; 240 int isempty; 241 size_t bufsize; 242 struct stat st; 243 struct dirent *dp; 244 char *buf, *ebuf, *cp; 245 CVSENTRIES *entlist; 246 247 cvs_log(LP_TRACE, "cvs_update_leavedir(%s)", cf->file_path); 248 249 if (cvs_server_active == 1 && !strcmp(cf->file_name, ".")) 250 return; 251 252 entlist = cvs_ent_open(cf->file_path); 253 if (!TAILQ_EMPTY(&(entlist->cef_ent))) { 254 isempty = 0; 255 goto prune_it; 256 } 257 258 if (fstat(cf->fd, &st) == -1) 259 fatal("cvs_update_leavedir: %s", strerror(errno)); 260 261 bufsize = st.st_size; 262 if (bufsize < st.st_blksize) 263 bufsize = st.st_blksize; 264 265 if (st.st_size > SIZE_MAX) 266 fatal("cvs_update_leavedir: %s: file size too big", 267 cf->file_name); 268 269 isempty = 1; 270 buf = xmalloc(bufsize); 271 272 if (lseek(cf->fd, 0, SEEK_SET) == -1) 273 fatal("cvs_update_leavedir: %s", strerror(errno)); 274 275 while ((nbytes = getdirentries(cf->fd, buf, bufsize, &base)) > 0) { 276 ebuf = buf + nbytes; 277 cp = buf; 278 279 while (cp < ebuf) { 280 dp = (struct dirent *)cp; 281 if (!strcmp(dp->d_name, ".") || 282 !strcmp(dp->d_name, "..") || 283 dp->d_fileno == 0) { 284 cp += dp->d_reclen; 285 continue; 286 } 287 288 if (strcmp(dp->d_name, CVS_PATH_CVSDIR)) 289 isempty = 0; 290 291 if (isempty == 0) 292 break; 293 294 cp += dp->d_reclen; 295 } 296 } 297 298 if (nbytes == -1) 299 fatal("cvs_update_leavedir: %s", strerror(errno)); 300 301 xfree(buf); 302 303 prune_it: 304 if ((isempty == 1 && prune_dirs == 1) || 305 (cvs_server_active == 1 && cvs_cmdop == CVS_OP_CHECKOUT)) { 306 /* XXX */ 307 cvs_rmdir(cf->file_path); 308 309 if (cvs_server_active == 0 && cvs_cmdop != CVS_OP_EXPORT) { 310 entlist = cvs_ent_open(cf->file_wd); 311 cvs_ent_remove(entlist, cf->file_name); 312 } 313 } 314 } 315 316 void 317 cvs_update_local(struct cvs_file *cf) 318 { 319 CVSENTRIES *entlist; 320 int ent_kflag, rcs_kflag, ret, flags; 321 char *tag, rbuf[CVS_REV_BUFSZ]; 322 323 cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path); 324 325 if (cf->file_type == CVS_DIR) { 326 if (cf->file_status == FILE_SKIP) { 327 if (cvs_cmdop == CVS_OP_EXPORT && verbosity > 0) 328 cvs_printf("? %s\n", cf->file_path); 329 return; 330 } 331 332 if (cf->file_status != FILE_UNKNOWN && 333 verbosity > 1) 334 cvs_log(LP_ERR, "Updating %s", cf->file_path); 335 return; 336 } 337 338 flags = 0; 339 if (cvs_specified_tag != NULL) 340 tag = cvs_specified_tag; 341 else if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL) 342 tag = cf->file_ent->ce_tag; 343 else 344 tag = cvs_directory_tag; 345 346 cvs_file_classify(cf, tag); 347 348 if (kflag && cf->file_rcs != NULL) 349 rcs_kwexp_set(cf->file_rcs, kflag); 350 351 if ((cf->file_status == FILE_UPTODATE || 352 cf->file_status == FILE_MODIFIED) && cf->file_ent != NULL && 353 cf->file_ent->ce_tag != NULL && reset_tag) { 354 if (cf->file_status == FILE_MODIFIED) 355 cf->file_status = FILE_MERGE; 356 else 357 cf->file_status = FILE_CHECKOUT; 358 359 if ((cf->file_rcsrev = rcs_head_get(cf->file_rcs)) == NULL) 360 fatal("no head revision in RCS file for %s", 361 cf->file_path); 362 363 /* might be a bit overkill */ 364 if (cvs_server_active == 1) 365 cvs_server_clear_sticky(cf->file_wd); 366 } 367 368 if (print_stdout) { 369 if (cf->file_status != FILE_UNKNOWN && cf->file_rcs != NULL && 370 cf->file_rcsrev != NULL && !cf->file_rcs->rf_dead && 371 (cf->file_flags & FILE_HAS_TAG)) { 372 rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf)); 373 if (verbosity > 1) { 374 cvs_log(LP_RCS, RCS_DIFF_DIV); 375 cvs_log(LP_RCS, "Checking out %s", 376 cf->file_path); 377 cvs_log(LP_RCS, "RCS: %s", cf->file_rpath); 378 cvs_log(LP_RCS, "VERS: %s", rbuf); 379 cvs_log(LP_RCS, "***************"); 380 } 381 cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_DUMP); 382 } 383 return; 384 } 385 386 if (cf->file_ent != NULL) { 387 if (cf->file_ent->ce_opts == NULL) { 388 if (kflag) 389 cf->file_status = FILE_CHECKOUT; 390 } else if (cf->file_rcs != NULL) { 391 if (strlen(cf->file_ent->ce_opts) < 3) 392 fatal("malformed option for file %s", 393 cf->file_path); 394 395 ent_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2); 396 rcs_kflag = rcs_kwexp_get(cf->file_rcs); 397 398 if ((kflag && (kflag != ent_kflag)) || 399 (reset_option && (ent_kflag != rcs_kflag))) 400 cf->file_status = FILE_CHECKOUT; 401 } 402 } 403 404 switch (cf->file_status) { 405 case FILE_UNKNOWN: 406 cvs_printf("? %s\n", cf->file_path); 407 break; 408 case FILE_MODIFIED: 409 if (backup_local_changes) { 410 cvs_backup_file(cf); 411 412 cvs_checkout_file(cf, cf->file_rcsrev, NULL, flags); 413 cvs_printf("U %s\n", cf->file_path); 414 } else { 415 ret = update_has_conflict_markers(cf); 416 if (cf->file_ent->ce_conflict != NULL && ret == 1) 417 cvs_printf("C %s\n", cf->file_path); 418 else { 419 if (cf->file_ent->ce_conflict != NULL && ret == 0) 420 update_clear_conflict(cf); 421 cvs_printf("M %s\n", cf->file_path); 422 } 423 } 424 break; 425 case FILE_ADDED: 426 cvs_printf("A %s\n", cf->file_path); 427 break; 428 case FILE_REMOVED: 429 cvs_printf("R %s\n", cf->file_path); 430 break; 431 case FILE_CONFLICT: 432 cvs_printf("C %s\n", cf->file_path); 433 break; 434 case FILE_LOST: 435 case FILE_CHECKOUT: 436 case FILE_PATCH: 437 if (!reset_tag && (tag != NULL || cvs_specified_date != -1 || 438 cvs_directory_date != -1 || (cf->file_ent != NULL && 439 cf->file_ent->ce_tag != NULL))) 440 flags = CO_SETSTICKY; 441 442 if (cf->file_flags & FILE_ON_DISK && (cf->file_ent == NULL || 443 cf->file_ent->ce_type == CVS_ENT_NONE)) { 444 cvs_log(LP_ERR, "move away %s; it is in the way", 445 cf->file_path); 446 cvs_printf("C %s\n", cf->file_path); 447 } else { 448 cvs_checkout_file(cf, cf->file_rcsrev, tag, flags); 449 cvs_printf("U %s\n", cf->file_path); 450 cvs_history_add(CVS_HISTORY_UPDATE_CO, cf, NULL); 451 } 452 break; 453 case FILE_MERGE: 454 d3rev1 = cf->file_ent->ce_rev; 455 d3rev2 = cf->file_rcsrev; 456 cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_MERGE); 457 458 if (diff3_conflicts != 0) { 459 cvs_printf("C %s\n", cf->file_path); 460 cvs_history_add(CVS_HISTORY_UPDATE_MERGED_ERR, 461 cf, NULL); 462 } else { 463 update_clear_conflict(cf); 464 cvs_printf("M %s\n", cf->file_path); 465 cvs_history_add(CVS_HISTORY_UPDATE_MERGED, cf, NULL); 466 } 467 break; 468 case FILE_UNLINK: 469 (void)unlink(cf->file_path); 470 case FILE_REMOVE_ENTRY: 471 entlist = cvs_ent_open(cf->file_wd); 472 cvs_ent_remove(entlist, cf->file_name); 473 cvs_history_add(CVS_HISTORY_UPDATE_REMOVE, cf, NULL); 474 475 if (cvs_server_active == 1) 476 cvs_checkout_file(cf, cf->file_rcsrev, tag, CO_REMOVE); 477 break; 478 case FILE_UPTODATE: 479 if (cvs_cmdop != CVS_OP_UPDATE) 480 break; 481 482 if (reset_tag != 1 && reset_option != 1) 483 break; 484 485 if (cf->file_ent != NULL && cf->file_ent->ce_tag == NULL) 486 break; 487 488 if (cf->file_rcs->rf_dead != 1 && 489 (cf->file_flags & FILE_HAS_TAG)) 490 cvs_checkout_file(cf, cf->file_rcsrev, 491 tag, CO_SETSTICKY); 492 break; 493 default: 494 break; 495 } 496 497 if (cvs_join_rev1 != NULL) 498 update_join_file(cf); 499 } 500 501 static void 502 update_clear_conflict(struct cvs_file *cf) 503 { 504 CVSENTRIES *entlist; 505 char *entry, revbuf[CVS_REV_BUFSZ]; 506 char sticky[CVS_ENT_MAXLINELEN], opt[4]; 507 508 cvs_log(LP_TRACE, "update_clear_conflict(%s)", cf->file_path); 509 510 rcsnum_tostr(cf->file_rcsrev, revbuf, sizeof(revbuf)); 511 512 sticky[0] = '\0'; 513 if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL) 514 (void)xsnprintf(sticky, sizeof(sticky), "T%s", 515 cf->file_ent->ce_tag); 516 517 opt[0] = '\0'; 518 if (cf->file_ent != NULL && cf->file_ent->ce_opts != NULL) 519 strlcpy(opt, cf->file_ent->ce_opts, sizeof(opt)); 520 521 entry = xmalloc(CVS_ENT_MAXLINELEN); 522 cvs_ent_line_str(cf->file_name, revbuf, "Result of merge", 523 opt[0] != '\0' ? opt : "", sticky, 0, 0, 524 entry, CVS_ENT_MAXLINELEN); 525 526 entlist = cvs_ent_open(cf->file_wd); 527 cvs_ent_add(entlist, entry); 528 xfree(entry); 529 } 530 531 /* 532 * XXX - this is the way GNU cvs checks for outstanding conflicts 533 * in a file after a merge. It is a very very bad approach and 534 * should be looked at once opencvs is working decently. 535 */ 536 int 537 update_has_conflict_markers(struct cvs_file *cf) 538 { 539 BUF *bp; 540 int conflict; 541 char *content; 542 struct rcs_line *lp; 543 struct rcs_lines *lines; 544 size_t len; 545 546 cvs_log(LP_TRACE, "update_has_conflict_markers(%s)", cf->file_path); 547 548 if (!(cf->file_flags & FILE_ON_DISK) || cf->file_ent == NULL) 549 return (0); 550 551 bp = buf_load_fd(cf->fd); 552 553 buf_putc(bp, '\0'); 554 len = buf_len(bp); 555 content = buf_release(bp); 556 if ((lines = cvs_splitlines(content, len)) == NULL) 557 fatal("update_has_conflict_markers: failed to split lines"); 558 559 conflict = 0; 560 TAILQ_FOREACH(lp, &(lines->l_lines), l_list) { 561 if (lp->l_line == NULL) 562 continue; 563 564 if (!strncmp(lp->l_line, RCS_CONFLICT_MARKER1, 565 sizeof(RCS_CONFLICT_MARKER1) - 1) || 566 !strncmp(lp->l_line, RCS_CONFLICT_MARKER2, 567 sizeof(RCS_CONFLICT_MARKER2) - 1) || 568 !strncmp(lp->l_line, RCS_CONFLICT_MARKER3, 569 sizeof(RCS_CONFLICT_MARKER3) - 1)) { 570 conflict = 1; 571 break; 572 } 573 } 574 575 cvs_freelines(lines); 576 xfree(content); 577 return (conflict); 578 } 579 580 void 581 update_join_file(struct cvs_file *cf) 582 { 583 time_t told; 584 RCSNUM *rev1, *rev2; 585 const char *state1, *state2; 586 char rbuf[CVS_REV_BUFSZ], *jrev1, *jrev2, *p; 587 588 rev1 = rev2 = NULL; 589 jrev1 = jrev2 = NULL; 590 591 jrev1 = xstrdup(cvs_join_rev1); 592 if (cvs_join_rev2 != NULL) 593 jrev2 = xstrdup(cvs_join_rev2); 594 595 if (jrev2 == NULL) { 596 jrev2 = jrev1; 597 jrev1 = NULL; 598 } 599 600 told = cvs_specified_date; 601 602 if ((p = strchr(jrev2, ':')) != NULL) { 603 (*p++) = '\0'; 604 if ((cvs_specified_date = date_parse(p)) == -1) { 605 cvs_printf("invalid date: %s", p); 606 goto out; 607 } 608 } 609 610 rev2 = rcs_translate_tag(jrev2, cf->file_rcs); 611 cvs_specified_date = told; 612 613 if (jrev1 != NULL) { 614 if ((p = strchr(jrev1, ':')) != NULL) { 615 (*p++) = '\0'; 616 if ((cvs_specified_date = date_parse(p)) == -1) { 617 cvs_printf("invalid date: %s", p); 618 goto out; 619 } 620 } 621 622 rev1 = rcs_translate_tag(jrev1, cf->file_rcs); 623 cvs_specified_date = told; 624 } else { 625 if (rev2 == NULL) 626 goto out; 627 628 rev1 = rcsnum_alloc(); 629 rcsnum_cpy(cf->file_rcsrev, rev1, 0); 630 } 631 632 state1 = state2 = RCS_STATE_DEAD; 633 634 if (rev1 != NULL) 635 state1 = rcs_state_get(cf->file_rcs, rev1); 636 if (rev2 != NULL) 637 state2 = rcs_state_get(cf->file_rcs, rev2); 638 639 if (rev2 == NULL || !strcmp(state2, RCS_STATE_DEAD)) { 640 if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) 641 goto out; 642 643 if (cf->file_status == FILE_REMOVED || 644 cf->file_rcs->rf_dead == 1) 645 goto out; 646 647 if (cf->file_status == FILE_MODIFIED || 648 cf->file_status == FILE_ADDED) 649 goto out; 650 651 (void)unlink(cf->file_path); 652 (void)close(cf->fd); 653 cf->fd = -1; 654 cvs_remove_local(cf); 655 goto out; 656 } 657 658 if (cf->file_ent != NULL) { 659 if (!rcsnum_cmp(cf->file_ent->ce_rev, rev2, 0)) 660 goto out; 661 } 662 663 if (cf->file_rcsrev == NULL) { 664 cvs_printf("non-mergable file: %s has no head revision!\n", 665 cf->file_path); 666 goto out; 667 } 668 669 if (rev1 == NULL || !strcmp(state1, RCS_STATE_DEAD)) { 670 if (cf->file_flags & FILE_ON_DISK) { 671 cvs_printf("%s exists but has been added in %s\n", 672 cf->file_path, jrev2); 673 } else { 674 cvs_printf("A %s\n", cf->file_path); 675 cvs_checkout_file(cf, cf->file_rcsrev, NULL, 0); 676 cvs_add_local(cf); 677 } 678 goto out; 679 } 680 681 if (!rcsnum_cmp(rev1, rev2, 0)) 682 goto out; 683 684 if (!(cf->file_flags & FILE_ON_DISK)) { 685 cvs_printf("%s does not exist but is present in %s\n", 686 cf->file_path, jrev2); 687 goto out; 688 } 689 690 if (rcs_kwexp_get(cf->file_rcs) & RCS_KWEXP_NONE) { 691 cvs_printf("non-mergable file: %s needs merge!\n", 692 cf->file_path); 693 goto out; 694 } 695 696 cvs_printf("joining "); 697 rcsnum_tostr(rev1, rbuf, sizeof(rbuf)); 698 cvs_printf("%s ", rbuf); 699 700 rcsnum_tostr(rev2, rbuf, sizeof(rbuf)); 701 cvs_printf("%s ", rbuf); 702 703 rcsnum_tostr(cf->file_rcsrev, rbuf, sizeof(rbuf)); 704 cvs_printf("into %s (%s)\n", cf->file_path, rbuf); 705 706 d3rev1 = rev1; 707 d3rev2 = rev2; 708 cvs_checkout_file(cf, cf->file_rcsrev, NULL, CO_MERGE); 709 710 if (diff3_conflicts == 0) 711 update_clear_conflict(cf); 712 713 out: 714 if (rev1 != NULL) 715 rcsnum_free(rev1); 716 if (rev2 != NULL) 717 rcsnum_free(rev2); 718 719 if (jrev1 != NULL) 720 xfree(jrev1); 721 if (jrev2 != NULL) 722 xfree(jrev2); 723 } 724 725 void 726 cvs_backup_file(struct cvs_file *cf) 727 { 728 char backup_name[MAXPATHLEN]; 729 char revstr[RCSNUM_MAXSTR]; 730 731 if (cf->file_status == FILE_ADDED) 732 (void)xsnprintf(revstr, sizeof(revstr), "0"); 733 else 734 rcsnum_tostr(cf->file_ent->ce_rev, revstr, sizeof(revstr)); 735 736 (void)xsnprintf(backup_name, MAXPATHLEN, "%s/.#%s.%s", 737 cf->file_wd, cf->file_name, revstr); 738 739 cvs_file_copy(cf->file_path, backup_name); 740 741 (void)xsnprintf(backup_name, MAXPATHLEN, ".#%s.%s", 742 cf->file_name, revstr); 743 cvs_printf("(Locally modified %s moved to %s)\n", 744 cf->file_name, backup_name); 745 } 746