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