checkout.c revision 26801
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 1.4 kit. 7 * 8 * Create Version 9 * 10 * "checkout" creates a "version" of an RCS repository. This version is owned 11 * totally by the user and is actually an independent copy, to be dealt with 12 * as seen fit. Once "checkout" has been called in a given directory, it 13 * never needs to be called again. The user can keep up-to-date by calling 14 * "update" when he feels like it; this will supply him with a merge of his 15 * own modifications and the changes made in the RCS original. See "update" 16 * for details. 17 * 18 * "checkout" can be given a list of directories or files to be updated and in 19 * the case of a directory, will recursivley create any sub-directories that 20 * exist in the repository. 21 * 22 * When the user is satisfied with his own modifications, the present version 23 * can be committed by "commit"; this keeps the present version in tact, 24 * usually. 25 * 26 * The call is cvs checkout [options] <module-name>... 27 * 28 * "checkout" creates a directory ./CVS, in which it keeps its administration, 29 * in two files, Repository and Entries. The first contains the name of the 30 * repository. The second contains one line for each registered file, 31 * consisting of the version number it derives from, its time stamp at 32 * derivation time and its name. Both files are normal files and can be 33 * edited by the user, if necessary (when the repository is moved, e.g.) 34 */ 35 36#include "cvs.h" 37 38static char *findslash PROTO((char *start, char *p)); 39static int checkout_proc PROTO((int *pargc, char **argv, char *where, 40 char *mwhere, char *mfile, int shorten, 41 int local_specified, char *omodule, 42 char *msg)); 43static int safe_location PROTO((void)); 44 45static const char *const checkout_usage[] = 46{ 47 "Usage:\n %s %s [-ANPRcflnps] [-r rev | -D date] [-d dir]\n", 48 " [-j rev1] [-j rev2] [-k kopt] modules...\n", 49 "\t-A\tReset any sticky tags/date/kopts.\n", 50 "\t-N\tDon't shorten module paths if -d specified.\n", 51 "\t-P\tPrune empty directories.\n", 52 "\t-R\tProcess directories recursively.\n", 53 "\t-c\t\"cat\" the module database.\n", 54 "\t-f\tForce a head revision match if tag/date not found.\n", 55 "\t-l\tLocal directory only, not recursive\n", 56 "\t-n\tDo not run module program (if any).\n", 57 "\t-p\tCheck out files to standard output (avoids stickiness).\n", 58 "\t-s\tLike -c, but include module status.\n", 59 "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n", 60 "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n", 61 "\t-d dir\tCheck out into dir instead of module name.\n", 62 "\t-k kopt\tUse RCS kopt -k option on checkout.\n", 63 "\t-j rev\tMerge in changes made between current revision and rev.\n", 64 NULL 65}; 66 67static const char *const export_usage[] = 68{ 69 "Usage: %s %s [-NRfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n", 70 "\t-N\tDon't shorten module paths if -d specified.\n", 71 "\t-f\tForce a head revision match if tag/date not found.\n", 72 "\t-l\tLocal directory only, not recursive\n", 73 "\t-R\tProcess directories recursively (default).\n", 74 "\t-n\tDo not run module program (if any).\n", 75 "\t-r rev\tExport revision or tag.\n", 76 "\t-D date\tExport revisions as of date.\n", 77 "\t-d dir\tExport into dir instead of module name.\n", 78 "\t-k kopt\tUse RCS kopt -k option on checkout.\n", 79 NULL 80}; 81 82static int checkout_prune_dirs; 83static int force_tag_match = 1; 84static int pipeout; 85static int aflag; 86static char *options = NULL; 87static char *tag = NULL; 88static int tag_validated = 0; 89static char *date = NULL; 90static char *join_rev1 = NULL; 91static char *join_rev2 = NULL; 92static int join_tags_validated = 0; 93static char *preload_update_dir = NULL; 94static char *history_name = NULL; 95 96int 97checkout (argc, argv) 98 int argc; 99 char **argv; 100{ 101 int i; 102 int c; 103 DBM *db; 104 int cat = 0, err = 0, status = 0; 105 int run_module_prog = 1; 106 int local = 0; 107 int shorten = -1; 108 char *where = NULL; 109 char *valid_options; 110 const char *const *valid_usage; 111 enum mtype m_type; 112 113 /* 114 * A smaller subset of options are allowed for the export command, which 115 * is essentially like checkout, except that it hard-codes certain 116 * options to be default (like -kv) and takes care to remove the CVS 117 * directory when it has done its duty 118 */ 119 if (strcmp (command_name, "export") == 0) 120 { 121 m_type = EXPORT; 122 valid_options = "+Nnk:d:flRQqr:D:"; 123 valid_usage = export_usage; 124 } 125 else 126 { 127 m_type = CHECKOUT; 128 valid_options = "+ANnk:d:flRpQqcsr:D:j:P"; 129 valid_usage = checkout_usage; 130 } 131 132 if (argc == -1) 133 usage (valid_usage); 134 135 ign_setup (); 136 wrap_setup (); 137 138 optind = 0; 139 while ((c = getopt (argc, argv, valid_options)) != -1) 140 { 141 switch (c) 142 { 143 case 'A': 144 aflag = 1; 145 break; 146 case 'N': 147 shorten = 0; 148 break; 149 case 'k': 150 if (options) 151 free (options); 152 options = RCS_check_kflag (optarg); 153 break; 154 case 'n': 155 run_module_prog = 0; 156 break; 157 case 'Q': 158 case 'q': 159#ifdef SERVER_SUPPORT 160 /* The CVS 1.5 client sends these options (in addition to 161 Global_option requests), so we must ignore them. */ 162 if (!server_active) 163#endif 164 error (1, 0, 165 "-q or -Q must be specified before \"%s\"", 166 command_name); 167 break; 168 case 'l': 169 local = 1; 170 break; 171 case 'R': 172 local = 0; 173 break; 174 case 'P': 175 checkout_prune_dirs = 1; 176 break; 177 case 'p': 178 pipeout = 1; 179 run_module_prog = 0; /* don't run module prog when piping */ 180 noexec = 1; /* so no locks will be created */ 181 break; 182 case 'c': 183 cat = 1; 184 break; 185 case 'd': 186 where = optarg; 187 if (shorten == -1) 188 shorten = 1; 189 break; 190 case 's': 191 status = 1; 192 break; 193 case 'f': 194 force_tag_match = 0; 195 break; 196 case 'r': 197 tag = optarg; 198 checkout_prune_dirs = 1; 199 break; 200 case 'D': 201 date = Make_Date (optarg); 202 checkout_prune_dirs = 1; 203 break; 204 case 'j': 205 if (join_rev2) 206 error (1, 0, "only two -j options can be specified"); 207 if (join_rev1) 208 join_rev2 = optarg; 209 else 210 join_rev1 = optarg; 211 break; 212 case '?': 213 default: 214 usage (valid_usage); 215 break; 216 } 217 } 218 argc -= optind; 219 argv += optind; 220 221 if (shorten == -1) 222 shorten = 0; 223 224 if ((cat || status) && argc != 0) 225 error (1, 0, "-c and -s must not get any arguments"); 226 227 if (!(cat || status) && argc == 0) 228 error (1, 0, "must specify at least one module or directory"); 229 230 if (where && pipeout) 231 error (1, 0, "-d and -p are mutually exclusive"); 232 233 if (strcmp (command_name, "export") == 0) 234 { 235 if (!tag && !date) 236 error (1, 0, "must specify a tag or date"); 237 238 if (tag && isdigit (tag[0])) 239 error (1, 0, "tag `%s' must be a symbolic tag", tag); 240 } 241 242 if (!safe_location()) { 243 error(1, 0, "Cannot check out files into the repository itself"); 244 } 245 246#ifdef CLIENT_SUPPORT 247 if (client_active) 248 { 249 int expand_modules; 250 251 start_server (); 252 253 ign_setup (); 254 255 /* We have to expand names here because the "expand-modules" 256 directive to the server has the side-effect of having the 257 server send the check-in and update programs for the 258 various modules/dirs requested. If we turn this off and 259 simply request the names of the modules and directories (as 260 below in !expand_modules), those files (CVS/Checking.prog 261 or CVS/Update.prog) don't get created. Grrr. */ 262 263 expand_modules = (!cat && !status && !pipeout 264 && supported_request ("expand-modules")); 265 266 if (expand_modules) 267 { 268 /* This is done here because we need to read responses 269 from the server before we send the command checkout or 270 export files. */ 271 272 client_expand_modules (argc, argv, local); 273 } 274 275 if (!run_module_prog) 276 send_arg ("-n"); 277 if (local) 278 send_arg ("-l"); 279 if (pipeout) 280 send_arg ("-p"); 281 if (!force_tag_match) 282 send_arg ("-f"); 283 if (aflag) 284 send_arg("-A"); 285 if (!shorten) 286 send_arg("-N"); 287 if (checkout_prune_dirs && strcmp (command_name, "export") != 0) 288 send_arg("-P"); 289 client_prune_dirs = checkout_prune_dirs; 290 if (cat) 291 send_arg("-c"); 292 if (where != NULL) 293 option_with_arg ("-d", where); 294 if (status) 295 send_arg("-s"); 296 if (options != NULL && options[0] != '\0') 297 send_arg (options); 298 option_with_arg ("-r", tag); 299 if (date) 300 client_senddate (date); 301 if (join_rev1 != NULL) 302 option_with_arg ("-j", join_rev1); 303 if (join_rev2 != NULL) 304 option_with_arg ("-j", join_rev2); 305 306 if (expand_modules) 307 { 308 client_send_expansions (local, where, 1); 309 } 310 else 311 { 312 int i; 313 for (i = 0; i < argc; ++i) 314 send_arg (argv[i]); 315 client_nonexpanded_setup (); 316 } 317 318 send_to_server (strcmp (command_name, "export") == 0 ? 319 "export\012" : "co\012", 320 0); 321 322 return get_responses_and_close (); 323 } 324#endif /* CLIENT_SUPPORT */ 325 326 if (cat || status) 327 { 328 cat_module (status); 329 if (options) 330 free (options); 331 return (0); 332 } 333 db = open_module (); 334 335 /* 336 * if we have more than one argument and where was specified, we make the 337 * where, cd into it, and try to shorten names as much as possible. 338 * Otherwise, we pass the where as a single argument to do_module. 339 */ 340 if (argc > 1 && where != NULL) 341 { 342 (void) CVS_MKDIR (where, 0777); 343 if ( CVS_CHDIR (where) < 0) 344 error (1, errno, "cannot chdir to %s", where); 345 preload_update_dir = xstrdup (where); 346 where = (char *) NULL; 347 if (!isfile (CVSADM)) 348 { 349 char *repository; 350 351 repository = xmalloc (strlen (CVSroot_directory) + 80); 352 (void) sprintf (repository, "%s/%s/%s", CVSroot_directory, 353 CVSROOTADM, CVSNULLREPOS); 354 if (!isfile (repository)) 355 { 356 mode_t omask; 357 omask = umask (cvsumask); 358 (void) CVS_MKDIR (repository, 0777); 359 (void) umask (omask); 360 } 361 362 /* I'm not sure whether this check is redundant. */ 363 if (!isdir (repository)) 364 error (1, 0, "there is no repository %s", repository); 365 366 Create_Admin (".", preload_update_dir, repository, 367 (char *) NULL, (char *) NULL, 0); 368 if (!noexec) 369 { 370 FILE *fp; 371 372 fp = open_file (CVSADM_ENTSTAT, "w+"); 373 if (fclose(fp) == EOF) 374 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 375#ifdef SERVER_SUPPORT 376 if (server_active) 377 server_set_entstat (preload_update_dir, repository); 378#endif 379 } 380 free (repository); 381 } 382 } 383 384 /* If we will be calling history_write, work out the name to pass 385 it. */ 386 if (strcmp (command_name, "export") != 0 && !pipeout) 387 { 388 if (tag && date) 389 { 390 history_name = xmalloc (strlen (tag) + strlen (date) + 2); 391 sprintf (history_name, "%s:%s", tag, date); 392 } 393 else if (tag) 394 history_name = tag; 395 else 396 history_name = date; 397 } 398 399 /* 400 * if where was specified (-d) and we have not taken care of it already 401 * with the multiple arg stuff, and it was not a simple directory name 402 * but rather a path, we strip off everything but the last component and 403 * attempt to cd to the indicated place. where then becomes simply the 404 * last component 405 */ 406 if (where != NULL && strchr (where, '/') != NULL) 407 { 408 char *slash; 409 410 slash = strrchr (where, '/'); 411 *slash = '\0'; 412 413 if ( CVS_CHDIR (where) < 0) 414 error (1, errno, "cannot chdir to %s", where); 415 416 preload_update_dir = xstrdup (where); 417 418 where = slash + 1; 419 if (*where == '\0') 420 where = NULL; 421 } 422 423 for (i = 0; i < argc; i++) 424 err += do_module (db, argv[i], m_type, "Updating", checkout_proc, 425 where, shorten, local, run_module_prog, 426 (char *) NULL); 427 close_module (db); 428 if (options) 429 free (options); 430 return (err); 431} 432 433static int 434safe_location () 435{ 436 char *current; 437 char hardpath[PATH_MAX+5]; 438 size_t hardpath_len; 439 int x; 440 int retval; 441 442#ifdef HAVE_READLINK 443 /* FIXME-arbitrary limit: should be retrying this like xgetwd. 444 But how does readlink let us know that the buffer was too small? 445 (by returning sizeof hardpath - 1?). */ 446 x = readlink(CVSroot_directory, hardpath, sizeof hardpath - 1); 447#else 448 x = -1; 449#endif 450 if (x == -1) 451 { 452 strcpy(hardpath, CVSroot_directory); 453 } 454 else 455 { 456 hardpath[x] = '\0'; 457 } 458 current = xgetwd (); 459 hardpath_len = strlen (hardpath); 460 if (strlen (current) >= hardpath_len 461 && strncmp (current, hardpath, hardpath_len) == 0) 462 { 463 if (/* Current is a subdirectory of hardpath. */ 464 current[hardpath_len] == '/' 465 466 /* Current is hardpath itself. */ 467 || current[hardpath_len] == '\0') 468 retval = 0; 469 else 470 /* It isn't a problem. For example, current is 471 "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot". */ 472 retval = 1; 473 } 474 else 475 retval = 1; 476 free (current); 477 return retval; 478} 479 480struct dir_to_build 481{ 482 /* What to put in CVS/Repository. */ 483 char *repository; 484 /* The path to the directory. */ 485 char *dirpath; 486 487 struct dir_to_build *next; 488}; 489 490static int build_dirs_and_chdir PROTO ((struct dir_to_build *list, 491 int sticky)); 492 493static void build_one_dir PROTO ((char *, char *, int)); 494 495static void 496build_one_dir (repository, dirpath, sticky) 497 char *repository; 498 char *dirpath; 499 int sticky; 500{ 501 FILE *fp; 502 503 if (!isfile (CVSADM) && strcmp (command_name, "export") != 0) 504 { 505 /* I suspect that this check could be omitted. */ 506 if (!isdir (repository)) 507 error (1, 0, "there is no repository %s", repository); 508 509 Create_Admin (".", dirpath, repository, 510 sticky ? (char *) NULL : tag, 511 sticky ? (char *) NULL : date, 512 513 /* FIXME? This is a guess. If it is important 514 for nonbranch to be set correctly here I 515 think we need to write it one way now and 516 then rewrite it later via WriteTag, once 517 we've had a chance to call RCS_nodeisbranch 518 on each file. */ 519 0); 520 521 if (!noexec) 522 { 523 fp = open_file (CVSADM_ENTSTAT, "w+"); 524 if (fclose (fp) == EOF) 525 error (1, errno, "cannot close %s", CVSADM_ENTSTAT); 526#ifdef SERVER_SUPPORT 527 if (server_active) 528 server_set_entstat (dirpath, repository); 529#endif 530 } 531 } 532} 533 534/* 535 * process_module calls us back here so we do the actual checkout stuff 536 */ 537/* ARGSUSED */ 538static int 539checkout_proc (pargc, argv, where, mwhere, mfile, shorten, 540 local_specified, omodule, msg) 541 int *pargc; 542 char **argv; 543 char *where; 544 char *mwhere; 545 char *mfile; 546 int shorten; 547 int local_specified; 548 char *omodule; 549 char *msg; 550{ 551 int err = 0; 552 int which; 553 char *cp; 554 char *cp2; 555 char *repository; 556 char *xwhere = NULL; 557 char *oldupdate = NULL; 558 char *prepath; 559 560 /* 561 * OK, so we're doing the checkout! Our args are as follows: 562 * argc,argv contain either dir or dir followed by a list of files 563 * where contains where to put it (if supplied by checkout) 564 * mwhere contains the module name or -d from module file 565 * mfile says do only that part of the module 566 * shorten = TRUE says shorten as much as possible 567 * omodule is the original arg to do_module() 568 */ 569 570 /* set up the repository (maybe) for the bottom directory */ 571 repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) + 5); 572 (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); 573 574 /* save the original value of preload_update_dir */ 575 if (preload_update_dir != NULL) 576 oldupdate = xstrdup (preload_update_dir); 577 578 /* fix up argv[] for the case of partial modules */ 579 if (mfile != NULL) 580 { 581 char *file; 582 583 /* if mfile is really a path, straighten it out first */ 584 if ((cp = strrchr (mfile, '/')) != NULL) 585 { 586 *cp = 0; 587 repository = xrealloc (repository, 588 strlen (repository) + strlen (mfile) + 10); 589 (void) strcat (repository, "/"); 590 (void) strcat (repository, mfile); 591 592 /* 593 * Now we need to fill in the where correctly. if !shorten, tack 594 * the rest of the path onto where if where is filled in 595 * otherwise tack the rest of the path onto mwhere and make that 596 * the where 597 * 598 * If shorten is enabled, we might use mwhere to set where if 599 * nobody set it yet, so we'll need to setup mwhere as the last 600 * component of the path we are tacking onto repository 601 */ 602 if (!shorten) 603 { 604 if (where != NULL) 605 { 606 xwhere = xmalloc (strlen (where) + strlen (mfile) + 5); 607 (void) sprintf (xwhere, "%s/%s", where, mfile); 608 } 609 else 610 { 611 xwhere = xmalloc (strlen (mwhere) + strlen (mfile) + 5); 612 (void) sprintf (xwhere, "%s/%s", mwhere, mfile); 613 } 614 where = xwhere; 615 } 616 else 617 { 618 char *slash; 619 620 if ((slash = strrchr (mfile, '/')) != NULL) 621 mwhere = slash + 1; 622 else 623 mwhere = mfile; 624 } 625 mfile = cp + 1; 626 } 627 628 file = xmalloc (strlen (repository) + strlen (mfile) + 5); 629 (void) sprintf (file, "%s/%s", repository, mfile); 630 if (isdir (file)) 631 { 632 633 /* 634 * The portion of a module was a directory, so kludge up where to 635 * be the subdir, and fix up repository 636 */ 637 free (repository); 638 repository = xstrdup (file); 639 640 /* 641 * At this point, if shorten is not enabled, we make where either 642 * where with mfile concatenated, or if where hadn't been set we 643 * set it to mwhere with mfile concatenated. 644 * 645 * If shorten is enabled and where hasn't been set yet, then where 646 * becomes mfile 647 */ 648 if (!shorten) 649 { 650 if (where != NULL) 651 { 652 xwhere = xmalloc (strlen (where) + strlen (mfile) + 5); 653 (void) sprintf (xwhere, "%s/%s", where, mfile); 654 } 655 else 656 { 657 xwhere = xmalloc (strlen (mwhere) + strlen (mfile) + 5); 658 (void) sprintf (xwhere, "%s/%s", mwhere, mfile); 659 } 660 where = xwhere; 661 } 662 else if (where == NULL) 663 where = mfile; 664 } 665 else 666 { 667 int i; 668 669 /* 670 * The portion of a module was a file, so kludge up argv to be 671 * correct 672 */ 673 for (i = 1; i < *pargc; i++)/* free the old ones */ 674 free (argv[i]); 675 /* FIXME: Normally one has to realloc argv to make sure 676 argv[1] exists. But this argv does not points to the 677 beginning of an allocated block. For now we allocate 678 at least 4 entries for argv (in line2argv). */ 679 argv[1] = xstrdup (mfile); /* set up the new one */ 680 *pargc = 2; 681 682 /* where gets mwhere if where isn't set */ 683 if (where == NULL) 684 where = mwhere; 685 } 686 free (file); 687 } 688 689 /* 690 * if shorten is enabled and where isn't specified yet, we pluck the last 691 * directory component of argv[0] and make it the where 692 */ 693 if (shorten && where == NULL) 694 { 695 if ((cp = strrchr (argv[0], '/')) != NULL) 696 { 697 xwhere = xstrdup (cp + 1); 698 where = xwhere; 699 } 700 } 701 702 /* if where is still NULL, use mwhere if set or the argv[0] dir */ 703 if (where == NULL) 704 { 705 if (mwhere) 706 where = mwhere; 707 else 708 { 709 xwhere = xstrdup (argv[0]); 710 where = xwhere; 711 } 712 } 713 714 if (preload_update_dir != NULL) 715 { 716 preload_update_dir = 717 xrealloc (preload_update_dir, 718 strlen (preload_update_dir) + strlen (where) + 5); 719 strcat (preload_update_dir, "/"); 720 strcat (preload_update_dir, where); 721 } 722 else 723 preload_update_dir = xstrdup (where); 724 725 /* 726 * At this point, where is the directory we want to build, repository is 727 * the repository for the lowest level of the path. 728 */ 729 730 /* 731 * If we are sending everything to stdout, we can skip a whole bunch of 732 * work from here 733 */ 734 if (!pipeout) 735 { 736 size_t root_len; 737 struct dir_to_build *head; 738 739 /* We need to tell build_dirs not only the path we want it to 740 build, but also the repositories we want it to populate the 741 path with. To accomplish this, we walk the path backwards, 742 one pathname component at a time, constucting a linked 743 list of struct dir_to_build. */ 744 prepath = xstrdup (repository); 745 746 /* We don't want to start stripping elements off prepath after we 747 get to CVSROOT. */ 748 root_len = strlen (CVSroot_directory); 749 if (strncmp (repository, CVSroot_directory, root_len) != 0) 750 error (1, 0, "\ 751internal error: %s doesn't start with %s in checkout_proc", 752 repository, CVSroot_directory); 753 754 /* We always create at least one directory, which corresponds to 755 the entire strings for WHERE and REPOSITORY. */ 756 head = (struct dir_to_build *) xmalloc (sizeof (struct dir_to_build)); 757 /* Special marker to indicate that we don't want build_dirs_and_chdir 758 to create the CVSADM directory for us. */ 759 head->repository = NULL; 760 head->dirpath = xstrdup (where); 761 head->next = NULL; 762 763 cp = strrchr (where, '/'); 764 cp2 = strrchr (prepath, '/'); 765 766 while (cp != NULL) 767 { 768 struct dir_to_build *new; 769 new = (struct dir_to_build *) 770 xmalloc (sizeof (struct dir_to_build)); 771 new->dirpath = xmalloc (strlen (where)); 772 strncpy (new->dirpath, where, cp - where); 773 new->dirpath[cp - where] = '\0'; 774 if (cp2 == NULL || cp2 < prepath + root_len) 775 { 776 /* Don't walk up past CVSROOT; instead put in CVSNULLREPOS. */ 777 new->repository = 778 xmalloc (strlen (CVSroot_directory) + 80); 779 (void) sprintf (new->repository, "%s/%s/%s", 780 CVSroot_directory, 781 CVSROOTADM, CVSNULLREPOS); 782 if (!isfile (new->repository)) 783 { 784 mode_t omask; 785 omask = umask (cvsumask); 786 if (CVS_MKDIR (new->repository, 0777) < 0) 787 error (0, errno, "cannot create %s", 788 new->repository); 789 (void) umask (omask); 790 } 791 } 792 else 793 { 794 new->repository = xmalloc (strlen (prepath)); 795 strncpy (new->repository, prepath, cp2 - prepath); 796 new->repository[cp2 - prepath] = '\0'; 797 } 798 new->next = head; 799 head = new; 800 801 cp = findslash (where, cp - 1); 802 cp2 = findslash (prepath, cp2 - 1); 803 } 804 805 /* First build the top-level CVSADM directory. The value we 806 pass in here for repository is probably wrong; see modules3-7f 807 in the testsuite. */ 808 build_one_dir (head->repository != NULL ? head->repository : prepath, 809 ".", *pargc <= 1); 810 811 /* 812 * build dirs on the path if necessary and leave us in the bottom 813 * directory (where if where was specified) doesn't contain a CVS 814 * subdir yet, but all the others contain CVS and Entries.Static 815 * files 816 */ 817 if (build_dirs_and_chdir (head, *pargc <= 1) != 0) 818 { 819 error (0, 0, "ignoring module %s", omodule); 820 free (prepath); 821 err = 1; 822 goto out; 823 } 824 825 /* clean up */ 826 free (prepath); 827 828 /* set up the repository (or make sure the old one matches) */ 829 if (!isfile (CVSADM)) 830 { 831 FILE *fp; 832 833 if (!noexec && *pargc > 1) 834 { 835 /* I'm not sure whether this check is redundant. */ 836 if (!isdir (repository)) 837 error (1, 0, "there is no repository %s", repository); 838 839 Create_Admin (".", preload_update_dir, repository, 840 (char *) NULL, (char *) NULL, 0); 841 fp = open_file (CVSADM_ENTSTAT, "w+"); 842 if (fclose(fp) == EOF) 843 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 844#ifdef SERVER_SUPPORT 845 if (server_active) 846 server_set_entstat (where, repository); 847#endif 848 } 849 else 850 { 851 /* I'm not sure whether this check is redundant. */ 852 if (!isdir (repository)) 853 error (1, 0, "there is no repository %s", repository); 854 855 Create_Admin (".", preload_update_dir, repository, tag, date, 856 857 /* FIXME? This is a guess. If it is important 858 for nonbranch to be set correctly here I 859 think we need to write it one way now and 860 then rewrite it later via WriteTag, once 861 we've had a chance to call RCS_nodeisbranch 862 on each file. */ 863 0); 864 } 865 } 866 else 867 { 868 char *repos; 869 870 /* get the contents of the previously existing repository */ 871 repos = Name_Repository ((char *) NULL, preload_update_dir); 872 if (fncmp (repository, repos) != 0) 873 { 874 error (0, 0, "existing repository %s does not match %s", 875 repos, repository); 876 error (0, 0, "ignoring module %s", omodule); 877 free (repos); 878 err = 1; 879 goto out; 880 } 881 free (repos); 882 } 883 } 884 885 /* 886 * If we are going to be updating to stdout, we need to cd to the 887 * repository directory so the recursion processor can use the current 888 * directory as the place to find repository information 889 */ 890 if (pipeout) 891 { 892 if ( CVS_CHDIR (repository) < 0) 893 { 894 error (0, errno, "cannot chdir to %s", repository); 895 err = 1; 896 goto out; 897 } 898 which = W_REPOS; 899 if (tag != NULL && !tag_validated) 900 { 901 tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL); 902 tag_validated = 1; 903 } 904 } 905 else 906 { 907 which = W_LOCAL | W_REPOS; 908 if (tag != NULL && !tag_validated) 909 { 910 tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, 911 repository); 912 tag_validated = 1; 913 } 914 } 915 916 if (tag != NULL || date != NULL || join_rev1 != NULL) 917 which |= W_ATTIC; 918 919 if (! join_tags_validated) 920 { 921 if (join_rev1 != NULL) 922 tag_check_valid_join (join_rev1, *pargc - 1, argv + 1, 0, aflag, 923 repository); 924 if (join_rev2 != NULL) 925 tag_check_valid_join (join_rev2, *pargc - 1, argv + 1, 0, aflag, 926 repository); 927 join_tags_validated = 1; 928 } 929 930 /* 931 * if we are going to be recursive (building dirs), go ahead and call the 932 * update recursion processor. We will be recursive unless either local 933 * only was specified, or we were passed arguments 934 */ 935 if (!(local_specified || *pargc > 1)) 936 { 937 if (strcmp (command_name, "export") != 0 && !pipeout) 938 history_write ('O', preload_update_dir, history_name, where, 939 repository); 940 else if (strcmp (command_name, "export") == 0 && !pipeout) 941 history_write ('E', preload_update_dir, tag ? tag : date, where, 942 repository); 943 err += do_update (0, (char **) NULL, options, tag, date, 944 force_tag_match, 0 /* !local */ , 945 1 /* update -d */ , aflag, checkout_prune_dirs, 946 pipeout, which, join_rev1, join_rev2, 947 preload_update_dir); 948 goto out; 949 } 950 951 if (!pipeout) 952 { 953 int i; 954 List *entries; 955 956 /* we are only doing files, so register them */ 957 entries = Entries_Open (0); 958 for (i = 1; i < *pargc; i++) 959 { 960 char *line; 961 Vers_TS *vers; 962 struct file_info finfo; 963 964 memset (&finfo, 0, sizeof finfo); 965 finfo.file = argv[i]; 966 /* Shouldn't be used, so set to arbitrary value. */ 967 finfo.update_dir = NULL; 968 finfo.fullname = argv[i]; 969 finfo.repository = repository; 970 finfo.entries = entries; 971 /* The rcs slot is needed to get the options from the RCS 972 file */ 973 finfo.rcs = RCS_parse (finfo.file, repository); 974 975 vers = Version_TS (&finfo, options, tag, date, 976 force_tag_match, 0); 977 if (vers->ts_user == NULL) 978 { 979 line = xmalloc (strlen (finfo.file) + 15); 980 (void) sprintf (line, "Initial %s", finfo.file); 981 Register (entries, finfo.file, 982 vers->vn_rcs ? vers->vn_rcs : "0", 983 line, vers->options, vers->tag, 984 vers->date, (char *) 0); 985 free (line); 986 } 987 freevers_ts (&vers); 988 freercsnode (&finfo.rcs); 989 } 990 991 Entries_Close (entries); 992 } 993 994 /* Don't log "export", just regular "checkouts" */ 995 if (strcmp (command_name, "export") != 0 && !pipeout) 996 history_write ('O', preload_update_dir, history_name, where, 997 repository); 998 999 /* go ahead and call update now that everything is set */ 1000 err += do_update (*pargc - 1, argv + 1, options, tag, date, 1001 force_tag_match, local_specified, 1 /* update -d */, 1002 aflag, checkout_prune_dirs, pipeout, which, join_rev1, 1003 join_rev2, preload_update_dir); 1004out: 1005 free (preload_update_dir); 1006 preload_update_dir = oldupdate; 1007 if (xwhere != NULL) 1008 free (xwhere); 1009 free (repository); 1010 return (err); 1011} 1012 1013static char * 1014findslash (start, p) 1015 char *start; 1016 char *p; 1017{ 1018 while (p >= start && *p != '/') 1019 p--; 1020 /* FIXME: indexing off the start of the array like this is *NOT* 1021 OK according to ANSI, and will break some of the time on certain 1022 segmented architectures. */ 1023 if (p < start) 1024 return (NULL); 1025 else 1026 return (p); 1027} 1028 1029/* Build all the dirs along the path to DIRS with CVS subdirs with appropriate 1030 repositories. If ->repository is NULL, do not create a CVSADM directory 1031 for that subdirectory; just CVS_CHDIR into it. */ 1032static int 1033build_dirs_and_chdir (dirs, sticky) 1034 struct dir_to_build *dirs; 1035 int sticky; 1036{ 1037 int retval = 0; 1038 struct dir_to_build *nextdir; 1039 1040 while (dirs != NULL) 1041 { 1042 char *dir = last_component (dirs->dirpath); 1043 1044 mkdir_if_needed (dir); 1045 Subdir_Register (NULL, NULL, dir); 1046 if (CVS_CHDIR (dir) < 0) 1047 { 1048 error (0, errno, "cannot chdir to %s", dir); 1049 retval = 1; 1050 goto out; 1051 } 1052 if (dirs->repository != NULL) 1053 { 1054 build_one_dir (dirs->repository, dirs->dirpath, sticky); 1055 free (dirs->repository); 1056 } 1057 nextdir = dirs->next; 1058 free (dirs->dirpath); 1059 free (dirs); 1060 dirs = nextdir; 1061 } 1062 1063 out: 1064 return retval; 1065} 1066