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