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