1 /* $OpenBSD: commit.c,v 1.152 2011/12/27 13:59:01 nicm Exp $ */ 2 /* 3 * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 4 * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/stat.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <libgen.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include "cvs.h" 28 #include "diff.h" 29 #include "remote.h" 30 31 void cvs_commit_local(struct cvs_file *); 32 void cvs_commit_check_files(struct cvs_file *); 33 void cvs_commit_loginfo(char *); 34 void cvs_commit_lock_dirs(struct cvs_file *); 35 36 static BUF *commit_diff(struct cvs_file *, RCSNUM *, int); 37 static void commit_desc_set(struct cvs_file *); 38 39 struct file_info_list files_info; 40 struct trigger_list *line_list; 41 42 struct cvs_flisthead files_affected; 43 struct cvs_flisthead files_added; 44 struct cvs_flisthead files_removed; 45 struct cvs_flisthead files_modified; 46 47 char *logmsg = NULL; 48 char *loginfo = NULL; 49 50 static int conflicts_found; 51 52 struct cvs_cmd cvs_cmd_commit = { 53 CVS_OP_COMMIT, CVS_USE_WDIR | CVS_LOCK_REPO, "commit", 54 { "ci", "com" }, 55 "Check files into the repository", 56 "[-flR] [-F logfile | -m msg] [-r rev] ...", 57 "F:flm:Rr:", 58 NULL, 59 cvs_commit 60 }; 61 62 int 63 cvs_commit(int argc, char **argv) 64 { 65 int flags; 66 int ch, Fflag, mflag; 67 struct module_checkout *mc; 68 struct cvs_recursion cr; 69 struct cvs_filelist *l; 70 struct file_info *fi; 71 char *arg = ".", repo[MAXPATHLEN]; 72 73 flags = CR_RECURSE_DIRS; 74 Fflag = mflag = 0; 75 76 while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) { 77 switch (ch) { 78 case 'F': 79 /* free previously assigned value */ 80 if (logmsg != NULL) 81 xfree(logmsg); 82 logmsg = cvs_logmsg_read(optarg); 83 Fflag = 1; 84 break; 85 case 'f': 86 break; 87 case 'l': 88 flags &= ~CR_RECURSE_DIRS; 89 break; 90 case 'm': 91 /* free previously assigned value */ 92 if (logmsg != NULL) 93 xfree(logmsg); 94 logmsg = xstrdup(optarg); 95 mflag = 1; 96 break; 97 case 'R': 98 flags |= CR_RECURSE_DIRS; 99 break; 100 case 'r': 101 break; 102 default: 103 fatal("%s", cvs_cmd_commit.cmd_synopsis); 104 } 105 } 106 107 argc -= optind; 108 argv += optind; 109 110 /* -F and -m are mutually exclusive */ 111 if (Fflag && mflag) 112 fatal("cannot specify both a log file and a message"); 113 114 RB_INIT(&files_affected); 115 RB_INIT(&files_added); 116 RB_INIT(&files_removed); 117 RB_INIT(&files_modified); 118 119 TAILQ_INIT(&files_info); 120 conflicts_found = 0; 121 122 cr.enterdir = NULL; 123 cr.leavedir = NULL; 124 cr.fileproc = cvs_commit_check_files; 125 cr.flags = flags; 126 127 if (argc > 0) 128 cvs_file_run(argc, argv, &cr); 129 else 130 cvs_file_run(1, &arg, &cr); 131 132 if (conflicts_found != 0) 133 fatal("%d conflicts found, please correct these first", 134 conflicts_found); 135 136 if (RB_EMPTY(&files_affected)) 137 return (0); 138 139 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 140 if (logmsg == NULL) { 141 logmsg = cvs_logmsg_create(NULL, &files_added, 142 &files_removed, &files_modified); 143 if (logmsg == NULL) 144 fatal("This shouldnt happen, honestly!"); 145 } 146 cvs_client_connect_to_server(); 147 cr.fileproc = cvs_client_sendfile; 148 149 if (argc > 0) 150 cvs_file_run(argc, argv, &cr); 151 else 152 cvs_file_run(1, &arg, &cr); 153 154 if (!(flags & CR_RECURSE_DIRS)) 155 cvs_client_send_request("Argument -l"); 156 157 cvs_client_send_logmsg(logmsg); 158 cvs_client_send_files(argv, argc); 159 cvs_client_senddir("."); 160 cvs_client_send_request("ci"); 161 cvs_client_get_responses(); 162 } else { 163 cvs_get_repository_name(".", repo, MAXPATHLEN); 164 165 line_list = cvs_trigger_getlines(CVS_PATH_COMMITINFO, repo); 166 if (line_list != NULL) { 167 RB_FOREACH(l, cvs_flisthead, &files_affected) { 168 fi = xcalloc(1, sizeof(*fi)); 169 fi->file_path = xstrdup(l->file_path); 170 TAILQ_INSERT_TAIL(&files_info, fi, 171 flist); 172 } 173 174 if (cvs_trigger_handle(CVS_TRIGGER_COMMITINFO, 175 repo, NULL, line_list, &files_info)) { 176 cvs_log(LP_ERR, 177 "Pre-commit check failed"); 178 cvs_trigger_freelist(line_list); 179 goto end; 180 } 181 182 cvs_trigger_freelist(line_list); 183 cvs_trigger_freeinfo(&files_info); 184 } 185 186 if (cvs_server_active) { 187 if (logmsg == NULL) 188 fatal("no log message specified"); 189 } else if (logmsg == NULL) { 190 logmsg = cvs_logmsg_create(NULL, &files_added, 191 &files_removed, &files_modified); 192 if (logmsg == NULL) 193 fatal("This shouldnt happen, honestly!"); 194 } 195 196 if (cvs_logmsg_verify(logmsg)) 197 goto end; 198 199 cr.fileproc = cvs_commit_lock_dirs; 200 cvs_file_walklist(&files_affected, &cr); 201 202 line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, repo); 203 204 cr.fileproc = cvs_commit_local; 205 cvs_file_walklist(&files_affected, &cr); 206 207 if (line_list != NULL) { 208 cvs_commit_loginfo(repo); 209 210 cvs_trigger_handle(CVS_TRIGGER_LOGINFO, repo, 211 loginfo, line_list, &files_info); 212 213 xfree(loginfo); 214 cvs_trigger_freelist(line_list); 215 cvs_trigger_freeinfo(&files_info); 216 } 217 218 mc = cvs_module_lookup(repo); 219 if (mc->mc_prog != NULL && 220 (mc->mc_flags & MODULE_RUN_ON_COMMIT)) 221 cvs_exec(mc->mc_prog, NULL, 0); 222 } 223 224 end: 225 cvs_trigger_freeinfo(&files_info); 226 if (logmsg != NULL) 227 xfree(logmsg); 228 return (0); 229 } 230 231 void 232 cvs_commit_loginfo(char *repo) 233 { 234 BUF *buf; 235 char pwd[MAXPATHLEN]; 236 struct cvs_filelist *cf; 237 238 if (getcwd(pwd, sizeof(pwd)) == NULL) 239 fatal("Can't get working directory"); 240 241 buf = buf_alloc(1024); 242 243 cvs_trigger_loginfo_header(buf, repo); 244 245 if (!RB_EMPTY(&files_added)) { 246 buf_puts(buf, "Added Files:"); 247 248 RB_FOREACH(cf, cvs_flisthead, &files_added) { 249 buf_putc(buf, '\n'); 250 buf_putc(buf, '\t'); 251 buf_puts(buf, cf->file_path); 252 } 253 254 buf_putc(buf, '\n'); 255 } 256 257 if (!RB_EMPTY(&files_modified)) { 258 buf_puts(buf, "Modified Files:"); 259 260 RB_FOREACH(cf, cvs_flisthead, &files_modified) { 261 buf_putc(buf, '\n'); 262 buf_putc(buf, '\t'); 263 buf_puts(buf, cf->file_path); 264 } 265 266 buf_putc(buf, '\n'); 267 } 268 269 if (!RB_EMPTY(&files_removed)) { 270 buf_puts(buf, "Removed Files:"); 271 272 RB_FOREACH(cf, cvs_flisthead, &files_removed) { 273 buf_putc(buf, '\n'); 274 buf_putc(buf, '\t'); 275 buf_puts(buf, cf->file_path); 276 } 277 278 buf_putc(buf, '\n'); 279 } 280 281 buf_puts(buf, "Log Message:\n"); 282 283 buf_puts(buf, logmsg); 284 285 buf_putc(buf, '\n'); 286 buf_putc(buf, '\0'); 287 288 loginfo = buf_release(buf); 289 } 290 291 void 292 cvs_commit_lock_dirs(struct cvs_file *cf) 293 { 294 char repo[MAXPATHLEN]; 295 296 cvs_get_repository_path(cf->file_wd, repo, sizeof(repo)); 297 cvs_log(LP_TRACE, "cvs_commit_lock_dirs: %s", repo); 298 299 /* locks stay in place until we are fully done and exit */ 300 cvs_repository_lock(repo, 1); 301 } 302 303 void 304 cvs_commit_check_files(struct cvs_file *cf) 305 { 306 char *tag; 307 RCSNUM *branch, *brev; 308 309 branch = brev = NULL; 310 311 cvs_log(LP_TRACE, "cvs_commit_check_files(%s)", cf->file_path); 312 313 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) 314 cvs_remote_classify_file(cf); 315 else 316 cvs_file_classify(cf, cvs_directory_tag); 317 318 if (cf->file_type == CVS_DIR) { 319 if (verbosity > 1) 320 cvs_log(LP_NOTICE, "Examining %s", cf->file_path); 321 return; 322 } 323 324 if (cf->file_status == FILE_UPTODATE) 325 return; 326 327 if (cf->file_status == FILE_MERGE || 328 cf->file_status == FILE_PATCH || 329 cf->file_status == FILE_CHECKOUT || 330 cf->file_status == FILE_LOST || 331 cf->file_status == FILE_UNLINK) { 332 cvs_log(LP_ERR, "conflict: %s is not up-to-date", 333 cf->file_path); 334 conflicts_found++; 335 return; 336 } 337 338 if (cf->file_status == FILE_CONFLICT && 339 cf->file_ent->ce_conflict != NULL) { 340 cvs_log(LP_ERR, "conflict: unresolved conflicts in %s from " 341 "merging, please fix these first", cf->file_path); 342 conflicts_found++; 343 return; 344 } 345 346 if (cf->file_status == FILE_MODIFIED && 347 cf->file_ent->ce_conflict != NULL && 348 update_has_conflict_markers(cf)) { 349 cvs_log(LP_ERR, "warning: file %s seems to still contain " 350 "conflict indicators", cf->file_path); 351 } 352 353 if (cf->file_ent != NULL && cf->file_ent->ce_date != -1) { 354 cvs_log(LP_ERR, "conflict: cannot commit to sticky date for %s", 355 cf->file_path); 356 conflicts_found++; 357 return; 358 } 359 360 if (current_cvsroot->cr_method == CVS_METHOD_LOCAL) { 361 tag = cvs_directory_tag; 362 if (cf->file_ent != NULL) 363 tag = cf->file_ent->ce_tag; 364 365 if (tag != NULL && cf->file_rcs != NULL) { 366 brev = rcs_sym_getrev(cf->file_rcs, tag); 367 if (brev != NULL) { 368 if (RCSNUM_ISBRANCH(brev)) 369 goto next; 370 rcsnum_free(brev); 371 } 372 373 brev = rcs_translate_tag(tag, cf->file_rcs); 374 375 if (brev == NULL) { 376 if (cf->file_status == FILE_ADDED) 377 goto next; 378 fatal("failed to resolve tag: %s", 379 cf->file_ent->ce_tag); 380 } 381 382 if ((branch = rcsnum_revtobr(brev)) == NULL) { 383 cvs_log(LP_ERR, "sticky tag %s is not " 384 "a branch for file %s", tag, 385 cf->file_path); 386 conflicts_found++; 387 rcsnum_free(brev); 388 return; 389 } 390 391 if (!RCSNUM_ISBRANCHREV(brev)) { 392 cvs_log(LP_ERR, "sticky tag %s is not " 393 "a branch for file %s", tag, 394 cf->file_path); 395 conflicts_found++; 396 rcsnum_free(branch); 397 rcsnum_free(brev); 398 return; 399 } 400 401 if (!RCSNUM_ISBRANCH(branch)) { 402 cvs_log(LP_ERR, "sticky tag %s is not " 403 "a branch for file %s", tag, 404 cf->file_path); 405 conflicts_found++; 406 rcsnum_free(branch); 407 rcsnum_free(brev); 408 return; 409 } 410 } 411 } 412 413 next: 414 if (branch != NULL) 415 rcsnum_free(branch); 416 if (brev != NULL) 417 rcsnum_free(brev); 418 419 if (cf->file_status != FILE_ADDED && 420 cf->file_status != FILE_REMOVED && 421 cf->file_status != FILE_MODIFIED) 422 return; 423 424 cvs_file_get(cf->file_path, 0, &files_affected, CVS_FILE); 425 426 switch (cf->file_status) { 427 case FILE_ADDED: 428 cvs_file_get(cf->file_path, 0, &files_added, CVS_FILE); 429 break; 430 case FILE_REMOVED: 431 cvs_file_get(cf->file_path, 0, &files_removed, CVS_FILE); 432 break; 433 case FILE_MODIFIED: 434 cvs_file_get(cf->file_path, 0, &files_modified, CVS_FILE); 435 break; 436 } 437 } 438 439 void 440 cvs_commit_local(struct cvs_file *cf) 441 { 442 char *tag; 443 BUF *b, *d; 444 int onbranch, isnew, histtype, branchadded; 445 RCSNUM *nrev, *crev, *rrev, *brev; 446 int openflags, rcsflags; 447 char rbuf[CVS_REV_BUFSZ], nbuf[CVS_REV_BUFSZ]; 448 CVSENTRIES *entlist; 449 char attic[MAXPATHLEN], repo[MAXPATHLEN], rcsfile[MAXPATHLEN]; 450 struct file_info *fi; 451 452 cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path); 453 cvs_file_classify(cf, cvs_directory_tag); 454 455 if (cvs_noexec == 1) 456 return; 457 458 if (cf->file_type != CVS_FILE) 459 fatal("cvs_commit_local: '%s' is not a file", cf->file_path); 460 461 tag = cvs_directory_tag; 462 if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL) 463 tag = cf->file_ent->ce_tag; 464 465 branchadded = 0; 466 switch (cf->file_status) { 467 case FILE_ADDED: 468 if (cf->file_rcs == NULL && tag != NULL) { 469 branchadded = 1; 470 cvs_add_tobranch(cf, tag); 471 } 472 break; 473 case FILE_MODIFIED: 474 case FILE_REMOVED: 475 if (cf->file_rcs == NULL) { 476 cvs_log(LP_ERR, "RCS file for %s got lost", 477 cf->file_path); 478 return; 479 } 480 break; 481 default: 482 cvs_log(LP_ERR, "skipping bogus file `%s'", cf->file_path); 483 return; 484 } 485 486 onbranch = 0; 487 nrev = RCS_HEAD_REV; 488 crev = NULL; 489 rrev = NULL; 490 d = NULL; 491 492 if (cf->file_rcs != NULL && cf->file_rcs->rf_branch != NULL) { 493 rcsnum_free(cf->file_rcs->rf_branch); 494 cf->file_rcs->rf_branch = NULL; 495 } 496 497 if (cf->file_rcs != NULL) { 498 rrev = rcs_head_get(cf->file_rcs); 499 crev = rcs_head_get(cf->file_rcs); 500 if (crev == NULL || rrev == NULL) 501 fatal("no head revision in RCS file for %s", 502 cf->file_path); 503 504 if (tag != NULL) { 505 rcsnum_free(crev); 506 rcsnum_free(rrev); 507 brev = rcs_sym_getrev(cf->file_rcs, tag); 508 crev = rcs_translate_tag(tag, cf->file_rcs); 509 if (brev == NULL || crev == NULL) { 510 fatal("failed to resolve existing tag: %s", 511 tag); 512 } 513 514 rrev = rcsnum_alloc(); 515 rcsnum_cpy(brev, rrev, brev->rn_len - 1); 516 517 if (RCSNUM_ISBRANCHREV(crev) && 518 rcsnum_cmp(crev, rrev, 0)) { 519 nrev = rcsnum_alloc(); 520 rcsnum_cpy(crev, nrev, 0); 521 rcsnum_inc(nrev); 522 } else if (!RCSNUM_ISBRANCH(crev)) { 523 nrev = rcsnum_brtorev(brev); 524 if (nrev == NULL) 525 fatal("failed to create branch rev"); 526 } else { 527 fatal("this isnt suppose to happen, honestly"); 528 } 529 530 rcsnum_free(brev); 531 rcsnum_free(rrev); 532 rrev = rcsnum_branch_root(nrev); 533 534 /* branch stuff was checked in cvs_commit_check_files */ 535 onbranch = 1; 536 } 537 538 rcsnum_tostr(crev, rbuf, sizeof(rbuf)); 539 } else { 540 strlcpy(rbuf, "Non-existent", sizeof(rbuf)); 541 } 542 543 if (rrev != NULL) 544 rcsnum_free(rrev); 545 isnew = 0; 546 if (cf->file_status == FILE_ADDED) { 547 isnew = 1; 548 rcsflags = RCS_CREATE; 549 openflags = O_CREAT | O_RDONLY; 550 if (cf->file_rcs != NULL) { 551 if (!onbranch) { 552 if (cf->in_attic == 0) 553 cvs_log(LP_ERR, "warning: expected %s " 554 "to be in the Attic", 555 cf->file_path); 556 557 if (cf->file_rcs->rf_dead == 0) 558 cvs_log(LP_ERR, "warning: expected %s " 559 "to be dead", cf->file_path); 560 561 cvs_get_repository_path(cf->file_wd, repo, 562 MAXPATHLEN); 563 (void)xsnprintf(rcsfile, MAXPATHLEN, "%s/%s%s", 564 repo, cf->file_name, RCS_FILE_EXT); 565 566 if (rename(cf->file_rpath, rcsfile) == -1) 567 fatal("cvs_commit_local: failed to " 568 "move %s outside the Attic: %s", 569 cf->file_path, strerror(errno)); 570 571 xfree(cf->file_rpath); 572 cf->file_rpath = xstrdup(rcsfile); 573 isnew = 0; 574 } 575 576 rcsflags = RCS_READ | RCS_PARSE_FULLY; 577 openflags = O_RDONLY; 578 rcs_close(cf->file_rcs); 579 } 580 581 cf->repo_fd = open(cf->file_rpath, openflags); 582 if (cf->repo_fd < 0) 583 fatal("cvs_commit_local: %s", strerror(errno)); 584 585 cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, 586 rcsflags, 0444); 587 if (cf->file_rcs == NULL) 588 fatal("cvs_commit_local: failed to create RCS file " 589 "for %s", cf->file_path); 590 591 commit_desc_set(cf); 592 593 if (branchadded) 594 strlcpy(rbuf, "Non-existent", sizeof(rbuf)); 595 } 596 597 if (verbosity > 1) { 598 cvs_printf("Checking in %s:\n", cf->file_path); 599 cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path); 600 cvs_printf("old revision: %s; ", rbuf); 601 } 602 603 if (isnew == 0 && cf->file_rcs->rf_head == NULL) 604 fatal("no head revision in RCS file for %s", cf->file_path); 605 606 if (isnew == 0 && onbranch == 0) 607 d = commit_diff(cf, cf->file_rcs->rf_head, 0); 608 609 if (cf->file_status == FILE_REMOVED) { 610 b = rcs_rev_getbuf(cf->file_rcs, crev, 0); 611 } else if (onbranch == 1) { 612 b = commit_diff(cf, crev, 1); 613 } else { 614 b = buf_load_fd(cf->fd); 615 } 616 617 if (isnew == 0 && onbranch == 0) { 618 if (rcs_deltatext_set(cf->file_rcs, crev, d) == -1) 619 fatal("cvs_commit_local: failed to set delta"); 620 } 621 622 if (rcs_rev_add(cf->file_rcs, nrev, logmsg, -1, NULL) == -1) 623 fatal("cvs_commit_local: failed to add new revision"); 624 625 if (nrev == RCS_HEAD_REV) 626 nrev = cf->file_rcs->rf_head; 627 628 if (rcs_deltatext_set(cf->file_rcs, nrev, b) == -1) 629 fatal("cvs_commit_local: failed to set new HEAD delta"); 630 631 if (cf->file_status == FILE_REMOVED) { 632 if (rcs_state_set(cf->file_rcs, nrev, RCS_STATE_DEAD) == -1) 633 fatal("cvs_commit_local: failed to set state"); 634 } 635 636 if (cf->file_status == FILE_ADDED && cf->file_ent->ce_opts != NULL) { 637 int cf_kflag; 638 639 cf_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2); 640 rcs_kwexp_set(cf->file_rcs, cf_kflag); 641 } 642 643 rcs_write(cf->file_rcs); 644 645 if (cf->file_status == FILE_REMOVED) { 646 strlcpy(nbuf, "Removed", sizeof(nbuf)); 647 } else if (cf->file_status == FILE_ADDED) { 648 if (cf->file_rcs->rf_dead == 1) 649 strlcpy(nbuf, "Initial Revision", sizeof(nbuf)); 650 else 651 rcsnum_tostr(nrev, nbuf, sizeof(nbuf)); 652 } else if (cf->file_status == FILE_MODIFIED) { 653 rcsnum_tostr(nrev, nbuf, sizeof(nbuf)); 654 } 655 656 if (verbosity > 1) 657 cvs_printf("new revision: %s\n", nbuf); 658 659 (void)unlink(cf->file_path); 660 (void)close(cf->fd); 661 cf->fd = -1; 662 663 if (cf->file_status != FILE_REMOVED) { 664 cvs_checkout_file(cf, nrev, NULL, CO_COMMIT); 665 } else { 666 entlist = cvs_ent_open(cf->file_wd); 667 cvs_ent_remove(entlist, cf->file_name); 668 669 cvs_get_repository_path(cf->file_wd, repo, MAXPATHLEN); 670 671 (void)xsnprintf(attic, MAXPATHLEN, "%s/%s", 672 repo, CVS_PATH_ATTIC); 673 674 if (mkdir(attic, 0755) == -1 && errno != EEXIST) 675 fatal("cvs_commit_local: failed to create Attic"); 676 677 (void)xsnprintf(attic, MAXPATHLEN, "%s/%s/%s%s", repo, 678 CVS_PATH_ATTIC, cf->file_name, RCS_FILE_EXT); 679 680 if (rename(cf->file_rpath, attic) == -1) 681 fatal("cvs_commit_local: failed to move %s to Attic", 682 cf->file_path); 683 684 if (cvs_server_active == 1) 685 cvs_server_update_entry("Remove-entry", cf); 686 } 687 688 if (verbosity > 1) 689 cvs_printf("done\n"); 690 else { 691 cvs_log(LP_NOTICE, "checking in '%s'; revision %s -> %s", 692 cf->file_path, rbuf, nbuf); 693 } 694 695 if (line_list != NULL) { 696 fi = xcalloc(1, sizeof(*fi)); 697 fi->file_path = xstrdup(cf->file_path); 698 fi->crevstr = xstrdup(rbuf); 699 fi->nrevstr = xstrdup(nbuf); 700 if (tag != NULL) 701 fi->tag_new = xstrdup(tag); 702 TAILQ_INSERT_TAIL(&files_info, fi, flist); 703 } 704 705 switch (cf->file_status) { 706 case FILE_MODIFIED: 707 histtype = CVS_HISTORY_COMMIT_MODIFIED; 708 break; 709 case FILE_ADDED: 710 histtype = CVS_HISTORY_COMMIT_ADDED; 711 break; 712 case FILE_REMOVED: 713 histtype = CVS_HISTORY_COMMIT_REMOVED; 714 break; 715 default: 716 histtype = -1; 717 break; 718 } 719 720 if (crev != NULL) 721 rcsnum_free(crev); 722 723 if (histtype != -1) 724 cvs_history_add(histtype, cf, NULL); 725 else 726 cvs_log(LP_NOTICE, "histtype was -1 for %s", cf->file_path); 727 } 728 729 static BUF * 730 commit_diff(struct cvs_file *cf, RCSNUM *rev, int reverse) 731 { 732 int fd1, fd2, d; 733 char *p1, *p2; 734 BUF *b; 735 736 (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 737 738 if (cf->file_status == FILE_MODIFIED || 739 cf->file_status == FILE_ADDED) { 740 b = buf_load_fd(cf->fd); 741 fd1 = buf_write_stmp(b, p1, NULL); 742 buf_free(b); 743 } else { 744 fd1 = rcs_rev_write_stmp(cf->file_rcs, rev, p1, 0); 745 } 746 747 (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 748 fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE); 749 750 b = buf_alloc(128); 751 752 diff_format = D_RCSDIFF; 753 754 if (reverse == 1) 755 d = diffreg(p2, p1, fd2, fd1, b, D_FORCEASCII); 756 else 757 d = diffreg(p1, p2, fd1, fd2, b, D_FORCEASCII); 758 if (d == D_ERROR) 759 fatal("commit_diff: failed to get RCS patch"); 760 761 close(fd1); 762 close(fd2); 763 764 xfree(p1); 765 xfree(p2); 766 767 return (b); 768 } 769 770 static void 771 commit_desc_set(struct cvs_file *cf) 772 { 773 BUF *bp; 774 int fd; 775 char desc_path[MAXPATHLEN], *desc; 776 777 (void)xsnprintf(desc_path, MAXPATHLEN, "%s/%s/%s%s", 778 cf->file_wd, CVS_PATH_CVSDIR, cf->file_name, CVS_DESCR_FILE_EXT); 779 780 if ((fd = open(desc_path, O_RDONLY)) == -1) 781 return; 782 783 bp = buf_load_fd(fd); 784 buf_putc(bp, '\0'); 785 desc = buf_release(bp); 786 787 rcs_desc_set(cf->file_rcs, desc); 788 789 (void)close(fd); 790 (void)cvs_unlink(desc_path); 791 792 xfree(desc); 793 } 794