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