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