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