add.c revision 66525
1/* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS source distribution. 7 * 8 * Add 9 * 10 * Adds a file or directory to the RCS source repository. For a file, 11 * the entry is marked as "needing to be added" in the user's own CVS 12 * directory, and really added to the repository when it is committed. 13 * For a directory, it is added at the appropriate place in the source 14 * repository and a CVS directory is generated within the directory. 15 * 16 * The -m option is currently the only supported option. Some may wish to 17 * supply standard "rcs" options here, but I've found that this causes more 18 * trouble than anything else. 19 * 20 * The user files or directories must already exist. For a directory, it must 21 * not already have a CVS file in it. 22 * 23 * An "add" on a file that has been "remove"d but not committed will cause the 24 * file to be resurrected. 25 */ 26 27#include "cvs.h" 28#include "savecwd.h" 29#include "fileattr.h" 30 31static int add_directory PROTO ((struct file_info *finfo)); 32static int build_entry PROTO((char *repository, char *user, char *options, 33 char *message, List * entries, char *tag)); 34 35static const char *const add_usage[] = 36{ 37 "Usage: %s %s [-k rcs-kflag] [-m message] files...\n", 38 "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n", 39 "\t-m\tUse \"message\" for the creation log.\n", 40 "(Specify the --help global option for a list of other help options)\n", 41 NULL 42}; 43 44int 45add (argc, argv) 46 int argc; 47 char **argv; 48{ 49 char *message = NULL; 50 int i; 51 char *repository; 52 int c; 53 int err = 0; 54 int added_files = 0; 55 char *options = NULL; 56 List *entries; 57 Vers_TS *vers; 58 struct saved_cwd cwd; 59 /* Nonzero if we found a slash, and are thus adding files in a 60 subdirectory. */ 61 int found_slash = 0; 62 size_t cvsroot_len; 63 64 if (argc == 1 || argc == -1) 65 usage (add_usage); 66 67 wrap_setup (); 68 69 /* parse args */ 70 optind = 0; 71 while ((c = getopt (argc, argv, "+k:m:")) != -1) 72 { 73 switch (c) 74 { 75 case 'k': 76 if (options) 77 free (options); 78 options = RCS_check_kflag (optarg); 79 break; 80 81 case 'm': 82 message = xstrdup (optarg); 83 break; 84 case '?': 85 default: 86 usage (add_usage); 87 break; 88 } 89 } 90 argc -= optind; 91 argv += optind; 92 93 if (argc <= 0) 94 usage (add_usage); 95 96 cvsroot_len = strlen (CVSroot_directory); 97 98 /* First some sanity checks. I know that the CVS case is (sort of) 99 also handled by add_directory, but we need to check here so the 100 client won't get all confused in send_file_names. */ 101 for (i = 0; i < argc; i++) 102 { 103 int skip_file = 0; 104 105 /* If it were up to me I'd probably make this a fatal error. 106 But some people are really fond of their "cvs add *", and 107 don't seem to object to the warnings. 108 Whatever. */ 109 strip_trailing_slashes (argv[i]); 110 if (strcmp (argv[i], ".") == 0 111 || strcmp (argv[i], "..") == 0 112 || fncmp (argv[i], CVSADM) == 0) 113 { 114 error (0, 0, "cannot add special file `%s'; skipping", argv[i]); 115 skip_file = 1; 116 } 117 else 118 { 119 char *p; 120 p = argv[i]; 121 while (*p != '\0') 122 { 123 if (ISDIRSEP (*p)) 124 { 125 found_slash = 1; 126 break; 127 } 128 ++p; 129 } 130 } 131 132 if (skip_file) 133 { 134 int j; 135 136 /* FIXME: We don't do anything about free'ing argv[i]. But 137 the problem is that it is only sometimes allocated (see 138 cvsrc.c). */ 139 140 for (j = i; j < argc - 1; ++j) 141 argv[j] = argv[j + 1]; 142 --argc; 143 /* Check the new argv[i] again. */ 144 --i; 145 ++err; 146 } 147 } 148 149#ifdef CLIENT_SUPPORT 150 if (client_active) 151 { 152 int i; 153 154 if (argc == 0) 155 /* We snipped out all the arguments in the above sanity 156 check. We can just forget the whole thing (and we 157 better, because if we fired up the server and passed it 158 nothing, it would spit back a usage message). */ 159 return err; 160 161 start_server (); 162 ign_setup (); 163 if (options) 164 { 165 send_arg (options); 166 free (options); 167 } 168 option_with_arg ("-m", message); 169 170 /* If !found_slash, refrain from sending "Directory", for 171 CVS 1.9 compatibility. If we only tried to deal with servers 172 which are at least CVS 1.9.26 or so, we wouldn't have to 173 special-case this. */ 174 if (found_slash) 175 { 176 repository = Name_Repository (NULL, NULL); 177 send_a_repository ("", repository, ""); 178 free (repository); 179 } 180 181 for (i = 0; i < argc; ++i) 182 { 183 /* FIXME: Does this erroneously call Create_Admin in error 184 conditions which are only detected once the server gets its 185 hands on things? */ 186 /* FIXME-also: if filenames are case-insensitive on the 187 client, and the directory in the repository already 188 exists and is named "foo", and the command is "cvs add 189 FOO", this call to Create_Admin puts the wrong thing in 190 CVS/Repository and so a subsequent "cvs update" will 191 give an error. The fix will be to have the server report 192 back what it actually did (e.g. use tagged text for the 193 "Directory %s added" message), and then Create_Admin, 194 which should also fix the error handling concerns. */ 195 196 if (isdir (argv[i])) 197 { 198 char *tag; 199 char *date; 200 int nonbranch; 201 char *rcsdir; 202 char *p; 203 char *update_dir; 204 /* This is some mungeable storage into which we can point 205 with p and/or update_dir. */ 206 char *filedir; 207 208 if (save_cwd (&cwd)) 209 error_exit (); 210 211 filedir = xstrdup (argv[i]); 212 p = last_component (filedir); 213 if (p == filedir) 214 { 215 update_dir = ""; 216 } 217 else 218 { 219 p[-1] = '\0'; 220 update_dir = filedir; 221 if (CVS_CHDIR (update_dir) < 0) 222 error (1, errno, 223 "could not chdir to %s", update_dir); 224 } 225 226 /* find the repository associated with our current dir */ 227 repository = Name_Repository (NULL, update_dir); 228 229 /* don't add stuff to Emptydir */ 230 if (strncmp (repository, CVSroot_directory, cvsroot_len) == 0 231 && ISDIRSEP (repository[cvsroot_len]) 232 && strncmp (repository + cvsroot_len + 1, 233 CVSROOTADM, 234 sizeof CVSROOTADM - 1) == 0 235 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM]) 236 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1, 237 CVSNULLREPOS) == 0) 238 error (1, 0, "cannot add to %s", repository); 239 240 /* before we do anything else, see if we have any 241 per-directory tags */ 242 ParseTag (&tag, &date, &nonbranch); 243 244 rcsdir = xmalloc (strlen (repository) + strlen (p) + 5); 245 sprintf (rcsdir, "%s/%s", repository, p); 246 247 Create_Admin (p, argv[i], rcsdir, tag, date, 248 nonbranch, 0, 1); 249 250 if (found_slash) 251 send_a_repository ("", repository, update_dir); 252 253 if (restore_cwd (&cwd, NULL)) 254 error_exit (); 255 free_cwd (&cwd); 256 257 if (tag) 258 free (tag); 259 if (date) 260 free (date); 261 free (rcsdir); 262 263 if (p == filedir) 264 Subdir_Register ((List *) NULL, (char *) NULL, argv[i]); 265 else 266 { 267 Subdir_Register ((List *) NULL, update_dir, p); 268 } 269 free (repository); 270 free (filedir); 271 } 272 } 273 send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS); 274 send_file_names (argc, argv, SEND_EXPAND_WILD); 275 send_to_server ("add\012", 0); 276 if (message) 277 free (message); 278 return err + get_responses_and_close (); 279 } 280#endif 281 282 /* walk the arg list adding files/dirs */ 283 for (i = 0; i < argc; i++) 284 { 285 int begin_err = err; 286#ifdef SERVER_SUPPORT 287 int begin_added_files = added_files; 288#endif 289 struct file_info finfo; 290 char *p; 291#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE) 292 char *found_name; 293#endif 294 295 memset (&finfo, 0, sizeof finfo); 296 297 if (save_cwd (&cwd)) 298 error_exit (); 299 300 finfo.fullname = xstrdup (argv[i]); 301 p = last_component (argv[i]); 302 if (p == argv[i]) 303 { 304 finfo.update_dir = ""; 305 finfo.file = p; 306 } 307 else 308 { 309 p[-1] = '\0'; 310 finfo.update_dir = argv[i]; 311 finfo.file = p; 312 if (CVS_CHDIR (finfo.update_dir) < 0) 313 error (1, errno, "could not chdir to %s", finfo.update_dir); 314 } 315 316 /* Add wrappers for this directory. They exist only until 317 the next call to wrap_add_file. */ 318 wrap_add_file (CVSDOTWRAPPER, 1); 319 320 finfo.rcs = NULL; 321 322 /* Find the repository associated with our current dir. */ 323 repository = Name_Repository (NULL, finfo.update_dir); 324 325 /* don't add stuff to Emptydir */ 326 if (strncmp (repository, CVSroot_directory, cvsroot_len) == 0 327 && ISDIRSEP (repository[cvsroot_len]) 328 && strncmp (repository + cvsroot_len + 1, 329 CVSROOTADM, 330 sizeof CVSROOTADM - 1) == 0 331 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM]) 332 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1, 333 CVSNULLREPOS) == 0) 334 error (1, 0, "cannot add to %s", repository); 335 336 entries = Entries_Open (0, NULL); 337 338 finfo.repository = repository; 339 finfo.entries = entries; 340 341#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE) 342 if (ign_case) 343 { 344 /* Need to check whether there is a directory with the 345 same name but different case. We'll check for files 346 with the same name later (when Version_TS calls 347 RCS_parse which calls fopen_case). If CVS some day 348 records directories in the RCS files, then we should be 349 able to skip the separate check here, which would be 350 cleaner. */ 351 DIR *dirp; 352 struct dirent *dp; 353 354 dirp = CVS_OPENDIR (finfo.repository); 355 if (dirp == NULL) 356 error (1, errno, "cannot read directory %s", finfo.repository); 357 found_name = NULL; 358 errno = 0; 359 while ((dp = readdir (dirp)) != NULL) 360 { 361 if (cvs_casecmp (dp->d_name, finfo.file) == 0) 362 { 363 if (found_name != NULL) 364 error (1, 0, "%s is ambiguous; could mean %s or %s", 365 finfo.file, dp->d_name, found_name); 366 found_name = xstrdup (dp->d_name); 367 } 368 } 369 if (errno != 0) 370 error (1, errno, "cannot read directory %s", finfo.repository); 371 closedir (dirp); 372 373 if (found_name != NULL) 374 { 375 /* OK, we are about to patch up the name, so patch up 376 the temporary directory too to match. The isdir 377 should "always" be true (since files have ,v), but 378 I guess we might as well make some attempt to not 379 get confused by stray files in the repository. */ 380 if (isdir (finfo.file)) 381 { 382 if (CVS_MKDIR (found_name, 0777) < 0 383 && errno != EEXIST) 384 error (0, errno, "cannot create %s", finfo.file); 385 } 386 387 /* OK, we found a directory with the same name, maybe in 388 a different case. Treat it as if the name were the 389 same. */ 390 finfo.file = found_name; 391 } 392 } 393#endif 394 395 /* We pass force_tag_match as 1. If the directory has a 396 sticky branch tag, and there is already an RCS file which 397 does not have that tag, then the head revision is 398 meaningless to us. */ 399 vers = Version_TS (&finfo, options, NULL, NULL, 1, 0); 400 if (vers->vn_user == NULL) 401 { 402 /* No entry available, ts_rcs is invalid */ 403 if (vers->vn_rcs == NULL) 404 { 405 /* There is no RCS file either */ 406 if (vers->ts_user == NULL) 407 { 408 /* There is no user file either */ 409 error (0, 0, "nothing known about %s", finfo.fullname); 410 err++; 411 } 412 else if (!isdir (finfo.file) 413 || wrap_name_has (finfo.file, WRAP_TOCVS)) 414 { 415 /* 416 * See if a directory exists in the repository with 417 * the same name. If so, blow this request off. 418 */ 419 char *dname = xmalloc (strlen (repository) 420 + strlen (finfo.file) 421 + 10); 422 (void) sprintf (dname, "%s/%s", repository, finfo.file); 423 if (isdir (dname)) 424 { 425 error (0, 0, 426 "cannot add file `%s' since the directory", 427 finfo.fullname); 428 error (0, 0, "`%s' already exists in the repository", 429 dname); 430 error (1, 0, "illegal filename overlap"); 431 } 432 free (dname); 433 434 if (vers->options == NULL || *vers->options == '\0') 435 { 436 /* No options specified on command line (or in 437 rcs file if it existed, e.g. the file exists 438 on another branch). Check for a value from 439 the wrapper stuff. */ 440 if (wrap_name_has (finfo.file, WRAP_RCSOPTION)) 441 { 442 if (vers->options) 443 free (vers->options); 444 vers->options = wrap_rcsoption (finfo.file, 1); 445 } 446 } 447 448 if (vers->nonbranch) 449 { 450 error (0, 0, 451 "cannot add file on non-branch tag %s", 452 vers->tag); 453 ++err; 454 } 455 else 456 { 457 /* There is a user file, so build the entry for it */ 458 if (build_entry (repository, finfo.file, vers->options, 459 message, entries, vers->tag) != 0) 460 err++; 461 else 462 { 463 added_files++; 464 if (!quiet) 465 { 466 if (vers->tag) 467 error (0, 0, "\ 468scheduling %s `%s' for addition on branch `%s'", 469 (wrap_name_has (finfo.file, 470 WRAP_TOCVS) 471 ? "wrapper" 472 : "file"), 473 finfo.fullname, vers->tag); 474 else 475 error (0, 0, 476 "scheduling %s `%s' for addition", 477 (wrap_name_has (finfo.file, 478 WRAP_TOCVS) 479 ? "wrapper" 480 : "file"), 481 finfo.fullname); 482 } 483 } 484 } 485 } 486 } 487 else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 488 { 489 if (isdir (finfo.file) 490 && !wrap_name_has (finfo.file, WRAP_TOCVS)) 491 { 492 error (0, 0, "\ 493the directory `%s' cannot be added because a file of the", finfo.fullname); 494 error (1, 0, "\ 495same name already exists in the repository."); 496 } 497 else 498 { 499 if (vers->nonbranch) 500 { 501 error (0, 0, 502 "cannot add file on non-branch tag %s", 503 vers->tag); 504 ++err; 505 } 506 else 507 { 508 if (vers->tag) 509 error (0, 0, "\ 510file `%s' will be added on branch `%s' from version %s", 511 finfo.fullname, vers->tag, vers->vn_rcs); 512 else 513 /* I'm not sure that mentioning 514 vers->vn_rcs makes any sense here; I 515 can't think of a way to word the 516 message which is not confusing. */ 517 error (0, 0, "\ 518re-adding file %s (in place of dead revision %s)", 519 finfo.fullname, vers->vn_rcs); 520 Register (entries, finfo.file, "0", vers->ts_user, 521 vers->options, 522 vers->tag, NULL, NULL); 523 ++added_files; 524 } 525 } 526 } 527 else 528 { 529 /* 530 * There is an RCS file already, so somebody else must've 531 * added it 532 */ 533 error (0, 0, "%s added independently by second party", 534 finfo.fullname); 535 err++; 536 } 537 } 538 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') 539 { 540 541 /* 542 * An entry for a new-born file, ts_rcs is dummy, but that is 543 * inappropriate here 544 */ 545 error (0, 0, "%s has already been entered", finfo.fullname); 546 err++; 547 } 548 else if (vers->vn_user[0] == '-') 549 { 550 /* An entry for a removed file, ts_rcs is invalid */ 551 if (vers->ts_user == NULL) 552 { 553 /* There is no user file (as it should be) */ 554 if (vers->vn_rcs == NULL) 555 { 556 557 /* 558 * There is no RCS file, so somebody else must've removed 559 * it from under us 560 */ 561 error (0, 0, "\ 562cannot resurrect %s; RCS file removed by second party", finfo.fullname); 563 err++; 564 } 565 else 566 { 567 568 /* 569 * There is an RCS file, so remove the "-" from the 570 * version number and restore the file 571 */ 572 char *tmp = xmalloc (strlen (finfo.file) + 50); 573 574 (void) strcpy (tmp, vers->vn_user + 1); 575 (void) strcpy (vers->vn_user, tmp); 576 (void) sprintf (tmp, "Resurrected %s", finfo.file); 577 Register (entries, finfo.file, vers->vn_user, tmp, 578 vers->options, 579 vers->tag, vers->date, vers->ts_conflict); 580 free (tmp); 581 582 /* XXX - bugs here; this really resurrect the head */ 583 /* Note that this depends on the Register above actually 584 having written Entries, or else it won't really 585 check the file out. */ 586 if (update (2, argv + i - 1) == 0) 587 { 588 error (0, 0, "%s, version %s, resurrected", 589 finfo.fullname, 590 vers->vn_user); 591 } 592 else 593 { 594 error (0, 0, "could not resurrect %s", finfo.fullname); 595 err++; 596 } 597 } 598 } 599 else 600 { 601 /* The user file shouldn't be there */ 602 error (0, 0, "\ 603%s should be removed and is still there (or is back again)", finfo.fullname); 604 err++; 605 } 606 } 607 else 608 { 609 /* A normal entry, ts_rcs is valid, so it must already be there */ 610 error (0, 0, "%s already exists, with version number %s", 611 finfo.fullname, 612 vers->vn_user); 613 err++; 614 } 615 freevers_ts (&vers); 616 617 /* passed all the checks. Go ahead and add it if its a directory */ 618 if (begin_err == err 619 && isdir (finfo.file) 620 && !wrap_name_has (finfo.file, WRAP_TOCVS)) 621 { 622 err += add_directory (&finfo); 623 } 624 else 625 { 626#ifdef SERVER_SUPPORT 627 if (server_active && begin_added_files != added_files) 628 server_checked_in (finfo.file, finfo.update_dir, repository); 629#endif 630 } 631 free (repository); 632 Entries_Close (entries); 633 634 if (restore_cwd (&cwd, NULL)) 635 error_exit (); 636 free_cwd (&cwd); 637 638 free (finfo.fullname); 639#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE) 640 if (ign_case && found_name != NULL) 641 free (found_name); 642#endif 643 } 644 if (added_files) 645 error (0, 0, "use '%s commit' to add %s permanently", 646 program_name, 647 (added_files == 1) ? "this file" : "these files"); 648 649 if (message) 650 free (message); 651 if (options) 652 free (options); 653 654 return (err); 655} 656 657/* 658 * The specified user file is really a directory. So, let's make sure that 659 * it is created in the RCS source repository, and that the user's directory 660 * is updated to include a CVS directory. 661 * 662 * Returns 1 on failure, 0 on success. 663 */ 664static int 665add_directory (finfo) 666 struct file_info *finfo; 667{ 668 char *repository = finfo->repository; 669 List *entries = finfo->entries; 670 char *dir = finfo->file; 671 672 char *rcsdir = NULL; 673 struct saved_cwd cwd; 674 char *message = NULL; 675 char *tag, *date; 676 int nonbranch; 677 char *attrs; 678 679 if (strchr (dir, '/') != NULL) 680 { 681 /* "Can't happen". */ 682 error (0, 0, 683 "directory %s not added; must be a direct sub-directory", dir); 684 return (1); 685 } 686 if (fncmp (dir, CVSADM) == 0) 687 { 688 error (0, 0, "cannot add a `%s' directory", CVSADM); 689 return (1); 690 } 691 692 /* before we do anything else, see if we have any per-directory tags */ 693 ParseTag (&tag, &date, &nonbranch); 694 695 /* Remember the default attributes from this directory, so we can apply 696 them to the new directory. */ 697 fileattr_startdir (repository); 698 attrs = fileattr_getall (NULL); 699 fileattr_free (); 700 701 /* now, remember where we were, so we can get back */ 702 if (save_cwd (&cwd)) 703 return (1); 704 if ( CVS_CHDIR (dir) < 0) 705 { 706 error (0, errno, "cannot chdir to %s", finfo->fullname); 707 return (1); 708 } 709#ifdef SERVER_SUPPORT 710 if (!server_active && isfile (CVSADM)) 711#else 712 if (isfile (CVSADM)) 713#endif 714 { 715 error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM); 716 goto out; 717 } 718 719 rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5); 720 sprintf (rcsdir, "%s/%s", repository, dir); 721 if (isfile (rcsdir) && !isdir (rcsdir)) 722 { 723 error (0, 0, "%s is not a directory; %s not added", rcsdir, 724 finfo->fullname); 725 goto out; 726 } 727 728 /* setup the log message */ 729 message = xmalloc (strlen (rcsdir) 730 + 80 731 + (tag == NULL ? 0 : strlen (tag) + 80) 732 + (date == NULL ? 0 : strlen (date) + 80)); 733 (void) sprintf (message, "Directory %s added to the repository\n", rcsdir); 734 if (tag) 735 { 736 (void) strcat (message, "--> Using per-directory sticky tag `"); 737 (void) strcat (message, tag); 738 (void) strcat (message, "'\n"); 739 } 740 if (date) 741 { 742 (void) strcat (message, "--> Using per-directory sticky date `"); 743 (void) strcat (message, date); 744 (void) strcat (message, "'\n"); 745 } 746 747 if (!isdir (rcsdir)) 748 { 749 mode_t omask; 750 Node *p; 751 List *ulist; 752 struct logfile_info *li; 753 754 /* There used to be some code here which would prompt for 755 whether to add the directory. The details of that code had 756 bitrotted, but more to the point it can't work 757 client/server, doesn't ask in the right way for GUIs, etc. 758 A better way of making it harder to accidentally add 759 directories would be to have to add and commit directories 760 like for files. The code was #if 0'd at least since CVS 1.5. */ 761 762 if (!noexec) 763 { 764 omask = umask (cvsumask); 765 if (CVS_MKDIR (rcsdir, 0777) < 0) 766 { 767 error (0, errno, "cannot mkdir %s", rcsdir); 768 (void) umask (omask); 769 goto out; 770 } 771 (void) umask (omask); 772 } 773 774 /* Now set the default file attributes to the ones we inherited 775 from the parent directory. */ 776 fileattr_startdir (rcsdir); 777 fileattr_setall (NULL, attrs); 778 fileattr_write (); 779 fileattr_free (); 780 if (attrs != NULL) 781 free (attrs); 782 783 /* 784 * Set up an update list with a single title node for Update_Logfile 785 */ 786 ulist = getlist (); 787 p = getnode (); 788 p->type = UPDATE; 789 p->delproc = update_delproc; 790 p->key = xstrdup ("- New directory"); 791 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); 792 li->type = T_TITLE; 793 li->tag = xstrdup (tag); 794 li->rev_old = li->rev_new = NULL; 795 p->data = (char *) li; 796 (void) addnode (ulist, p); 797 Update_Logfile (rcsdir, message, (FILE *) NULL, ulist); 798 dellist (&ulist); 799 } 800 801#ifdef SERVER_SUPPORT 802 if (!server_active) 803#endif 804 Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1); 805 if (tag) 806 free (tag); 807 if (date) 808 free (date); 809 810 if (restore_cwd (&cwd, NULL)) 811 error_exit (); 812 free_cwd (&cwd); 813 814 Subdir_Register (entries, (char *) NULL, dir); 815 816 cvs_output (message, 0); 817 818 free (rcsdir); 819 free (message); 820 821 return (0); 822 823out: 824 if (restore_cwd (&cwd, NULL)) 825 error_exit (); 826 free_cwd (&cwd); 827 if (rcsdir != NULL) 828 free (rcsdir); 829 return (0); 830} 831 832/* 833 * Builds an entry for a new file and sets up "CVS/file",[pt] by 834 * interrogating the user. Returns non-zero on error. 835 */ 836static int 837build_entry (repository, user, options, message, entries, tag) 838 char *repository; 839 char *user; 840 char *options; 841 char *message; 842 List *entries; 843 char *tag; 844{ 845 char *fname; 846 char *line; 847 FILE *fp; 848 849 if (noexec) 850 return (0); 851 852 /* 853 * The requested log is read directly from the user and stored in the 854 * file user,t. If the "message" argument is set, use it as the 855 * initial creation log (which typically describes the file). 856 */ 857 fname = xmalloc (strlen (user) + 80); 858 (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG); 859 fp = open_file (fname, "w+"); 860 if (message && fputs (message, fp) == EOF) 861 error (1, errno, "cannot write to %s", fname); 862 if (fclose(fp) == EOF) 863 error(1, errno, "cannot close %s", fname); 864 free (fname); 865 866 /* 867 * Create the entry now, since this allows the user to interrupt us above 868 * without needing to clean anything up (well, we could clean up the 869 * ,t file, but who cares). 870 */ 871 line = xmalloc (strlen (user) + 20); 872 (void) sprintf (line, "Initial %s", user); 873 Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); 874 free (line); 875 return (0); 876} 877