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