checkout.c revision 81404
117680Spst/* 239297Sfenner * Copyright (c) 1992, Brian Berliner and Jeff Polk 317680Spst * Copyright (c) 1989-1992, Brian Berliner 417680Spst * 517680Spst * You may distribute under the terms of the GNU General Public License as 617680Spst * specified in the README file that comes with the CVS source distribution. 717680Spst * 817680Spst * Create Version 917680Spst * 1017680Spst * "checkout" creates a "version" of an RCS repository. This version is owned 1117680Spst * totally by the user and is actually an independent copy, to be dealt with 1217680Spst * as seen fit. Once "checkout" has been called in a given directory, it 1317680Spst * never needs to be called again. The user can keep up-to-date by calling 1417680Spst * "update" when he feels like it; this will supply him with a merge of his 1517680Spst * own modifications and the changes made in the RCS original. See "update" 1617680Spst * for details. 1717680Spst * 1817680Spst * "checkout" can be given a list of directories or files to be updated and in 1917680Spst * the case of a directory, will recursivley create any sub-directories that 2017680Spst * exist in the repository. 2117680Spst * 2217680Spst * When the user is satisfied with his own modifications, the present version 2317680Spst * can be committed by "commit"; this keeps the present version in tact, 2417680Spst * usually. 25127668Sbms * 26190207Srpaulo * The call is cvs checkout [options] <module-name>... 2717680Spst * 2817680Spst * "checkout" creates a directory ./CVS, in which it keeps its administration, 2956893Sfenner * in two files, Repository and Entries. The first contains the name of the 3056893Sfenner * repository. The second contains one line for each registered file, 3156893Sfenner * consisting of the version number it derives from, its time stamp at 3256893Sfenner * derivation time and its name. Both files are normal files and can be 33127668Sbms * edited by the user, if necessary (when the repository is moved, e.g.) 3417680Spst */ 3517680Spst 3617680Spst#include <assert.h> 3739297Sfenner#include "cvs.h" 3817680Spst 3917680Spststatic char *findslash PROTO((char *start, char *p)); 4075115Sfennerstatic int checkout_proc PROTO((int argc, char **argv, char *where, 4117680Spst char *mwhere, char *mfile, int shorten, 4217680Spst int local_specified, char *omodule, 4317680Spst char *msg)); 4417680Spst 4517680Spststatic const char *const checkout_usage[] = 4617680Spst{ 4717680Spst "Usage:\n %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n", 4817680Spst " [-j rev1] [-j rev2] [-k kopt] modules...\n", 4917680Spst "\t-A\tReset any sticky tags/date/kopts.\n", 5017680Spst "\t-N\tDon't shorten module paths if -d specified.\n", 5117680Spst "\t-P\tPrune empty directories.\n", 5217680Spst "\t-R\tProcess directories recursively.\n", 5317680Spst "\t-c\t\"cat\" the module database.\n", 5417680Spst "\t-f\tForce a head revision match if tag/date not found.\n", 5517680Spst "\t-l\tLocal directory only, not recursive\n", 5617680Spst "\t-n\tDo not run module program (if any).\n", 5717680Spst "\t-p\tCheck out files to standard output (avoids stickiness).\n", 5817680Spst "\t-s\tLike -c, but include module status.\n", 5917680Spst "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n", 6017680Spst "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n", 6117680Spst "\t-d dir\tCheck out into dir instead of module name.\n", 6217680Spst "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", 6317680Spst "\t-j rev\tMerge in changes made between current revision and rev.\n", 6417680Spst "(Specify the --help global option for a list of other help options)\n", 6517680Spst NULL 6617680Spst}; 6717680Spst 6817680Spststatic const char *const export_usage[] = 6917680Spst{ 7017680Spst "Usage: %s %s [-NRfln] [-r rev] [-D date] [-d dir] [-k kopt] module...\n", 7117680Spst "\t-N\tDon't shorten module paths if -d specified.\n", 7217680Spst "\t-f\tForce a head revision match if tag/date not found.\n", 7317680Spst "\t-l\tLocal directory only, not recursive\n", 7417680Spst "\t-R\tProcess directories recursively (default).\n", 7517680Spst "\t-n\tDo not run module program (if any).\n", 7617680Spst "\t-r rev\tExport revision or tag.\n", 7717680Spst "\t-D date\tExport revisions as of date.\n", 7817680Spst "\t-d dir\tExport into dir instead of module name.\n", 7917680Spst "\t-k kopt\tUse RCS kopt -k option on checkout.\n", 80147899Ssam "(Specify the --help global option for a list of other help options)\n", 8117680Spst NULL 8217680Spst}; 8317680Spst 8417680Spststatic int checkout_prune_dirs; 8517680Spststatic int force_tag_match = 1; 8617680Spststatic int pipeout; 8717680Spststatic int aflag; 8898524Sfennerstatic char *options = NULL; 8917680Spststatic char *tag = NULL; 9017680Spststatic int tag_validated = 0; 9117680Spststatic char *date = NULL; 9217680Spststatic char *join_rev1 = NULL; 9317680Spststatic char *join_rev2 = NULL; 9417680Spststatic int join_tags_validated = 0; 9517680Spststatic char *preload_update_dir = NULL; 9617680Spststatic char *history_name = NULL; 9775115Sfennerstatic enum mtype m_type; 9875115Sfenner 9917680Spstint 10017680Spstcheckout (argc, argv) 10117680Spst int argc; 10217680Spst char **argv; 10317680Spst{ 10417680Spst int i; 10517680Spst int c; 10617680Spst DBM *db; 10717680Spst int cat = 0, err = 0, status = 0; 10817680Spst int run_module_prog = 1; 10917680Spst int local = 0; 11017680Spst int shorten = -1; 11117680Spst char *where = NULL; 11217680Spst char *valid_options; 11317680Spst const char *const *valid_usage; 11417680Spst 11517680Spst /* 11617680Spst * A smaller subset of options are allowed for the export command, which 11717680Spst * is essentially like checkout, except that it hard-codes certain 11817680Spst * options to be default (like -kv) and takes care to remove the CVS 11917680Spst * directory when it has done its duty 12098524Sfenner */ 12117680Spst if (strcmp (command_name, "export") == 0) 12217680Spst { 12317680Spst m_type = EXPORT; 12417680Spst valid_options = "+Nnk:d:flRQqr:D:"; 12517680Spst valid_usage = export_usage; 12617680Spst } 12717680Spst else 12817680Spst { 12998524Sfenner m_type = CHECKOUT; 13017680Spst valid_options = "+ANnk:d:flRpQqcsr:D:j:P"; 131 valid_usage = checkout_usage; 132 } 133 134 if (argc == -1) 135 usage (valid_usage); 136 137 ign_setup (); 138 wrap_setup (); 139 140 optind = 0; 141 while ((c = getopt (argc, argv, valid_options)) != -1) 142 { 143 switch (c) 144 { 145 case 'A': 146 aflag = 1; 147 break; 148 case 'N': 149 shorten = 0; 150 break; 151 case 'k': 152 if (options) 153 free (options); 154 options = RCS_check_kflag (optarg); 155 break; 156 case 'n': 157 run_module_prog = 0; 158 break; 159 case 'Q': 160 case 'q': 161#ifdef SERVER_SUPPORT 162 /* The CVS 1.5 client sends these options (in addition to 163 Global_option requests), so we must ignore them. */ 164 if (!server_active) 165#endif 166 error (1, 0, 167 "-q or -Q must be specified before \"%s\"", 168 command_name); 169 break; 170 case 'l': 171 local = 1; 172 break; 173 case 'R': 174 local = 0; 175 break; 176 case 'P': 177 checkout_prune_dirs = 1; 178 break; 179 case 'p': 180 pipeout = 1; 181 run_module_prog = 0; /* don't run module prog when piping */ 182 noexec = 1; /* so no locks will be created */ 183 break; 184 case 'c': 185 cat = 1; 186 break; 187 case 'd': 188 where = optarg; 189 if (shorten == -1) 190 shorten = 1; 191 break; 192 case 's': 193 cat = status = 1; 194 break; 195 case 'f': 196 force_tag_match = 0; 197 break; 198 case 'r': 199 tag = optarg; 200 checkout_prune_dirs = 1; 201 break; 202 case 'D': 203 date = Make_Date (optarg); 204 checkout_prune_dirs = 1; 205 break; 206 case 'j': 207 if (join_rev2) 208 error (1, 0, "only two -j options can be specified"); 209 if (join_rev1) 210 join_rev2 = optarg; 211 else 212 join_rev1 = optarg; 213 break; 214 case '?': 215 default: 216 usage (valid_usage); 217 break; 218 } 219 } 220 argc -= optind; 221 argv += optind; 222 223 if (shorten == -1) 224 shorten = 0; 225 226 if (cat && argc != 0) 227 error (1, 0, "-c and -s must not get any arguments"); 228 229 if (!cat && argc == 0) 230 error (1, 0, "must specify at least one module or directory"); 231 232 if (where && pipeout) 233 error (1, 0, "-d and -p are mutually exclusive"); 234 235 if (m_type == EXPORT) 236 { 237 if (!tag && !date) 238 error (1, 0, "must specify a tag or date"); 239 240 if (tag && isdigit ((unsigned char) tag[0])) 241 error (1, 0, "tag `%s' must be a symbolic tag", tag); 242 } 243 244#ifdef SERVER_SUPPORT 245 if (server_active && where != NULL) 246 { 247 server_pathname_check (where); 248 } 249#endif 250 251 if (!cat && !safe_location()) { 252 error(1, 0, "Cannot check out files into the repository itself"); 253 } 254 255#ifdef CLIENT_SUPPORT 256 if (current_parsed_root->isremote) 257 { 258 int expand_modules; 259 260 start_server (); 261 262 ign_setup (); 263 264 /* We have to expand names here because the "expand-modules" 265 directive to the server has the side-effect of having the 266 server send the check-in and update programs for the 267 various modules/dirs requested. If we turn this off and 268 simply request the names of the modules and directories (as 269 below in !expand_modules), those files (CVS/Checkin.prog 270 or CVS/Update.prog) don't get created. Grrr. */ 271 272 expand_modules = (!cat && !pipeout 273 && supported_request ("expand-modules")); 274 275 if (expand_modules) 276 { 277 /* This is done here because we need to read responses 278 from the server before we send the command checkout or 279 export files. */ 280 281 client_expand_modules (argc, argv, local); 282 } 283 284 if (!run_module_prog) 285 send_arg ("-n"); 286 if (local) 287 send_arg ("-l"); 288 if (pipeout) 289 send_arg ("-p"); 290 if (!force_tag_match) 291 send_arg ("-f"); 292 if (aflag) 293 send_arg("-A"); 294 if (!shorten) 295 send_arg("-N"); 296 if (checkout_prune_dirs && m_type == CHECKOUT) 297 send_arg("-P"); 298 client_prune_dirs = checkout_prune_dirs; 299 if (cat && !status) 300 send_arg("-c"); 301 if (where != NULL) 302 option_with_arg ("-d", where); 303 if (status) 304 send_arg("-s"); 305 if (options != NULL && options[0] != '\0') 306 send_arg (options); 307 option_with_arg ("-r", tag); 308 if (date) 309 client_senddate (date); 310 if (join_rev1 != NULL) 311 option_with_arg ("-j", join_rev1); 312 if (join_rev2 != NULL) 313 option_with_arg ("-j", join_rev2); 314 315 if (expand_modules) 316 { 317 client_send_expansions (local, where, 1); 318 } 319 else 320 { 321 int i; 322 for (i = 0; i < argc; ++i) 323 send_arg (argv[i]); 324 client_nonexpanded_setup (); 325 } 326 327 send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0); 328 return get_responses_and_close (); 329 } 330#endif /* CLIENT_SUPPORT */ 331 332 if (cat) 333 { 334 cat_module (status); 335 if (options) 336 free (options); 337 return (0); 338 } 339 db = open_module (); 340 341 342 /* If we've specified something like "cvs co foo/bar baz/quux" 343 don't try to shorten names. There are a few cases in which we 344 could shorten (e.g. "cvs co foo/bar foo/baz"), but we don't 345 handle those yet. Better to have an extra directory created 346 than the thing checked out under the wrong directory name. */ 347 348 if (argc > 1) 349 shorten = 0; 350 351 352 /* If we will be calling history_write, work out the name to pass 353 it. */ 354 if (m_type == CHECKOUT && !pipeout) 355 { 356 if (tag && date) 357 { 358 history_name = xmalloc (strlen (tag) + strlen (date) + 2); 359 sprintf (history_name, "%s:%s", tag, date); 360 } 361 else if (tag) 362 history_name = tag; 363 else 364 history_name = date; 365 } 366 367 368 for (i = 0; i < argc; i++) 369 err += do_module (db, argv[i], m_type, "Updating", checkout_proc, 370 where, shorten, local, run_module_prog, !pipeout, 371 (char *) NULL); 372 close_module (db); 373 if (options) 374 free (options); 375 return (err); 376} 377 378/* FIXME: This is and emptydir_name are in checkout.c for historical 379 reasons, probably want to move them. */ 380 381int 382safe_location () 383{ 384 char *current; 385 char hardpath[PATH_MAX+5]; 386 size_t hardpath_len; 387 int x; 388 int retval; 389 390#ifdef HAVE_READLINK 391 /* FIXME-arbitrary limit: should be retrying this like xgetwd. 392 But how does readlink let us know that the buffer was too small? 393 (by returning sizeof hardpath - 1?). */ 394 x = readlink(current_parsed_root->directory, hardpath, sizeof hardpath - 1); 395#else 396 x = -1; 397#endif 398 if (x == -1) 399 { 400 strcpy(hardpath, current_parsed_root->directory); 401 } 402 else 403 { 404 hardpath[x] = '\0'; 405 } 406 current = xgetwd (); 407 if (current == NULL) 408 error (1, errno, "could not get working directory"); 409 hardpath_len = strlen (hardpath); 410 if (strlen (current) >= hardpath_len 411 && strncmp (current, hardpath, hardpath_len) == 0) 412 { 413 if (/* Current is a subdirectory of hardpath. */ 414 current[hardpath_len] == '/' 415 416 /* Current is hardpath itself. */ 417 || current[hardpath_len] == '\0') 418 retval = 0; 419 else 420 /* It isn't a problem. For example, current is 421 "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot". */ 422 retval = 1; 423 } 424 else 425 retval = 1; 426 free (current); 427 return retval; 428} 429 430struct dir_to_build 431{ 432 /* What to put in CVS/Repository. */ 433 char *repository; 434 /* The path to the directory. */ 435 char *dirpath; 436 437 /* If set, don't build the directory, just change to it. 438 The caller will also want to set REPOSITORY to NULL. */ 439 int just_chdir; 440 441 struct dir_to_build *next; 442}; 443 444static int build_dirs_and_chdir PROTO ((struct dir_to_build *list, 445 int sticky)); 446 447static void build_one_dir PROTO ((char *, char *, int)); 448 449static void 450build_one_dir (repository, dirpath, sticky) 451 char *repository; 452 char *dirpath; 453 int sticky; 454{ 455 FILE *fp; 456 457 if (isfile (CVSADM)) 458 { 459 if (m_type == EXPORT) 460 error (1, 0, "cannot export into a working directory"); 461 } 462 else if (m_type == CHECKOUT) 463 { 464 /* I suspect that this check could be omitted. */ 465 if (!isdir (repository)) 466 error (1, 0, "there is no repository %s", repository); 467 468 if (Create_Admin (".", dirpath, repository, 469 sticky ? tag : (char *) NULL, 470 sticky ? date : (char *) NULL, 471 472 /* FIXME? This is a guess. If it is important 473 for nonbranch to be set correctly here I 474 think we need to write it one way now and 475 then rewrite it later via WriteTag, once 476 we've had a chance to call RCS_nodeisbranch 477 on each file. */ 478 0, 1, 1)) 479 return; 480 481 if (!noexec) 482 { 483 fp = open_file (CVSADM_ENTSTAT, "w+"); 484 if (fclose (fp) == EOF) 485 error (1, errno, "cannot close %s", CVSADM_ENTSTAT); 486#ifdef SERVER_SUPPORT 487 if (server_active) 488 server_set_entstat (dirpath, repository); 489#endif 490 } 491 } 492} 493 494/* 495 * process_module calls us back here so we do the actual checkout stuff 496 */ 497/* ARGSUSED */ 498static int 499checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, 500 local_specified, omodule, msg) 501 int argc; 502 char **argv; 503 char *where_orig; 504 char *mwhere; 505 char *mfile; 506 int shorten; 507 int local_specified; 508 char *omodule; 509 char *msg; 510{ 511 char *myargv[2]; 512 int err = 0; 513 int which; 514 char *cp; 515 char *repository; 516 char *oldupdate = NULL; 517 char *where; 518 519 /* 520 * OK, so we're doing the checkout! Our args are as follows: 521 * argc,argv contain either dir or dir followed by a list of files 522 * where contains where to put it (if supplied by checkout) 523 * mwhere contains the module name or -d from module file 524 * mfile says do only that part of the module 525 * shorten = 1 says shorten as much as possible 526 * omodule is the original arg to do_module() 527 */ 528 529 /* Set up the repository (maybe) for the bottom directory. 530 Allocate more space than we need so we don't need to keep 531 reallocating this string. */ 532 repository = xmalloc (strlen (current_parsed_root->directory) 533 + strlen (argv[0]) 534 + (mfile == NULL ? 0 : strlen (mfile)) 535 + 10); 536 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); 537 Sanitize_Repository_Name (repository); 538 539 540 /* save the original value of preload_update_dir */ 541 if (preload_update_dir != NULL) 542 oldupdate = xstrdup (preload_update_dir); 543 544 545 /* Allocate space and set up the where variable. We allocate more 546 space than necessary here so that we don't have to keep 547 reallocaing it later on. */ 548 549 where = xmalloc (strlen (argv[0]) 550 + (mfile == NULL ? 0 : strlen (mfile)) 551 + (mwhere == NULL ? 0 : strlen (mwhere)) 552 + (where_orig == NULL ? 0 : strlen (where_orig)) 553 + 10); 554 555 /* Yes, this could be written in a less verbose way, but in this 556 form it is quite easy to read. 557 558 FIXME? The following code that sets should probably be moved 559 to do_module in modules.c, since there is similar code in 560 patch.c and rtag.c. */ 561 562 if (shorten) 563 { 564 if (where_orig != NULL) 565 { 566 /* If the user has specified a directory with `-d' on the 567 command line, use it preferentially, even over the `-d' 568 flag in the modules file. */ 569 570 (void) strcpy (where, where_orig); 571 } 572 else if (mwhere != NULL) 573 { 574 /* Second preference is the value of mwhere, which is from 575 the `-d' flag in the modules file. */ 576 577 (void) strcpy (where, mwhere); 578 } 579 else 580 { 581 /* Third preference is the directory specified in argv[0] 582 which is this module'e directory in the repository. */ 583 584 (void) strcpy (where, argv[0]); 585 } 586 } 587 else 588 { 589 /* Use the same preferences here, bug don't shorten -- that 590 is, tack on where_orig if it exists. */ 591 592 *where = '\0'; 593 594 if (where_orig != NULL) 595 { 596 (void) strcat (where, where_orig); 597 (void) strcat (where, "/"); 598 } 599 600 /* If the -d flag in the modules file specified an absolute 601 directory, let the user override it with the command-line 602 -d option. */ 603 604 if ((mwhere != NULL) && (! isabsolute (mwhere))) 605 (void) strcat (where, mwhere); 606 else 607 (void) strcat (where, argv[0]); 608 } 609 strip_trailing_slashes (where); /* necessary? */ 610 611 612 /* At this point, the user may have asked for a single file or 613 directory from within a module. In that case, we should modify 614 where, repository, and argv as appropriate. */ 615 616 if (mfile != NULL) 617 { 618 /* The mfile variable can have one or more path elements. If 619 it has multiple elements, we want to tack those onto both 620 repository and where. The last element may refer to either 621 a file or directory. Here's what to do: 622 623 it refers to a directory 624 -> simply tack it on to where and repository 625 it refers to a file 626 -> munge argv to contain `basename mfile` */ 627 628 char *cp; 629 char *path; 630 631 632 /* Paranoia check. */ 633 634 if (mfile[strlen (mfile) - 1] == '/') 635 { 636 error (0, 0, "checkout_proc: trailing slash on mfile (%s)!", 637 mfile); 638 } 639 640 641 /* Does mfile have multiple path elements? */ 642 643 cp = strrchr (mfile, '/'); 644 if (cp != NULL) 645 { 646 *cp = '\0'; 647 (void) strcat (repository, "/"); 648 (void) strcat (repository, mfile); 649 (void) strcat (where, "/"); 650 (void) strcat (where, mfile); 651 mfile = cp + 1; 652 } 653 654 655 /* Now mfile is a single path element. */ 656 657 path = xmalloc (strlen (repository) + strlen (mfile) + 5); 658 (void) sprintf (path, "%s/%s", repository, mfile); 659 if (isdir (path)) 660 { 661 /* It's a directory, so tack it on to repository and 662 where, as we did above. */ 663 664 (void) strcat (repository, "/"); 665 (void) strcat (repository, mfile); 666 (void) strcat (where, "/"); 667 (void) strcat (where, mfile); 668 } 669 else 670 { 671 /* It's a file, which means we have to screw around with 672 argv. */ 673 myargv[0] = argv[0]; 674 myargv[1] = mfile; 675 argc = 2; 676 argv = myargv; 677 } 678 free (path); 679 } 680 681 if (preload_update_dir != NULL) 682 { 683 preload_update_dir = 684 xrealloc (preload_update_dir, 685 strlen (preload_update_dir) + strlen (where) + 5); 686 strcat (preload_update_dir, "/"); 687 strcat (preload_update_dir, where); 688 } 689 else 690 preload_update_dir = xstrdup (where); 691 692 /* 693 * At this point, where is the directory we want to build, repository is 694 * the repository for the lowest level of the path. 695 * 696 * We need to tell build_dirs not only the path we want it to 697 * build, but also the repositories we want it to populate the 698 * path with. To accomplish this, we walk the path backwards, one 699 * pathname component at a time, constucting a linked list of 700 * struct dir_to_build. 701 */ 702 703 /* 704 * If we are sending everything to stdout, we can skip a whole bunch of 705 * work from here 706 */ 707 if (!pipeout) 708 { 709 struct dir_to_build *head; 710 char *reposcopy; 711 712 if (strncmp (repository, current_parsed_root->directory, 713 strlen (current_parsed_root->directory)) != 0) 714 error (1, 0, "\ 715internal error: %s doesn't start with %s in checkout_proc", 716 repository, current_parsed_root->directory); 717 718 /* We always create at least one directory, which corresponds to 719 the entire strings for WHERE and REPOSITORY. */ 720 head = (struct dir_to_build *) xmalloc (sizeof (struct dir_to_build)); 721 /* Special marker to indicate that we don't want build_dirs_and_chdir 722 to create the CVSADM directory for us. */ 723 head->repository = NULL; 724 head->dirpath = xstrdup (where); 725 head->next = NULL; 726 head->just_chdir = 0; 727 728 729 /* Make a copy of the repository name to play with. */ 730 reposcopy = xstrdup (repository); 731 732 /* FIXME: this should be written in terms of last_component 733 instead of hardcoding '/'. This presumably affects OS/2, 734 NT, &c, if the user specifies '\'. Likewise for the call 735 to findslash. */ 736 cp = where + strlen (where); 737 while (cp > where) 738 { 739 struct dir_to_build *new; 740 741 cp = findslash (where, cp - 1); 742 if (cp == NULL) 743 break; /* we're done */ 744 745 new = (struct dir_to_build *) 746 xmalloc (sizeof (struct dir_to_build)); 747 new->dirpath = xmalloc (strlen (where)); 748 749 /* If the user specified an absolute path for where, the 750 last path element we create should be the top-level 751 directory. */ 752 753 if (cp > where) 754 { 755 strncpy (new->dirpath, where, cp - where); 756 new->dirpath[cp - where] = '\0'; 757 } 758 else 759 { 760 /* where should always be at least one character long. */ 761 assert (where[0] != '\0'); 762 strcpy (new->dirpath, "/"); 763 } 764 new->next = head; 765 head = new; 766 767 /* If where consists of multiple pathname components, 768 then we want to just cd into it, without creating 769 directories or modifying CVS directories as we go. 770 In CVS 1.9 and earlier, the code actually does a 771 CVS_CHDIR up-front; I'm not going to try to go back 772 to that exact code but this is somewhat similar 773 in spirit. */ 774 if (where_orig != NULL 775 && cp - where < strlen (where_orig)) 776 { 777 new->repository = NULL; 778 new->just_chdir = 1; 779 continue; 780 } 781 782 new->just_chdir = 0; 783 784 /* Now figure out what repository directory to generate. 785 The most complete case would be something like this: 786 787 The modules file contains 788 foo -d bar/baz quux 789 790 The command issued was: 791 cvs co -d what/ever -N foo 792 793 The results in the CVS/Repository files should be: 794 . -> (don't touch CVS/Repository) 795 (I think this case might be buggy currently) 796 what -> (don't touch CVS/Repository) 797 ever -> . (same as "cd what/ever; cvs co -N foo") 798 bar -> Emptydir (generated dir -- not in repos) 799 baz -> quux (finally!) */ 800 801 if (strcmp (reposcopy, current_parsed_root->directory) == 0) 802 { 803 /* We can't walk up past CVSROOT. Instead, the 804 repository should be Emptydir. */ 805 new->repository = emptydir_name (); 806 } 807 else 808 { 809 /* It's a directory in the repository! */ 810 811 char *rp; 812 813 /* We'll always be below CVSROOT, but check for 814 paranoia's sake. */ 815 rp = strrchr (reposcopy, '/'); 816 if (rp == NULL) 817 error (1, 0, 818 "internal error: %s doesn't contain a slash", 819 reposcopy); 820 821 *rp = '\0'; 822 new->repository = xmalloc (strlen (reposcopy) + 5); 823 (void) strcpy (new->repository, reposcopy); 824 825 if (strcmp (reposcopy, current_parsed_root->directory) == 0) 826 { 827 /* Special case -- the repository name needs 828 to be "/path/to/repos/." (the trailing dot 829 is important). We might be able to get rid 830 of this after the we check out the other 831 code that handles repository names. */ 832 (void) strcat (new->repository, "/."); 833 } 834 } 835 } 836 837 /* clean up */ 838 free (reposcopy); 839 840 { 841 int where_is_absolute = isabsolute (where); 842 843 /* The top-level CVSADM directory should always be 844 current_parsed_root->directory. Create it, but only if WHERE is 845 relative. If WHERE is absolute, our current directory 846 may not have a thing to do with where the sources are 847 being checked out. If it does, build_dirs_and_chdir 848 will take care of creating adm files here. */ 849 /* FIXME: checking where_is_absolute is a horrid kludge; 850 I suspect we probably can just skip the call to 851 build_one_dir whenever the -d command option was specified 852 to checkout. */ 853 854 if (! where_is_absolute && top_level_admin) 855 { 856 /* It may be argued that we shouldn't set any sticky 857 bits for the top-level repository. FIXME? */ 858 build_one_dir (current_parsed_root->directory, ".", argc <= 1); 859 860#ifdef SERVER_SUPPORT 861 /* We _always_ want to have a top-level admin 862 directory. If we're running in client/server mode, 863 send a "Clear-static-directory" command to make 864 sure it is created on the client side. (See 5.10 865 in cvsclient.dvi to convince yourself that this is 866 OK.) If this is a duplicate command being sent, it 867 will be ignored on the client side. */ 868 869 if (server_active) 870 server_clear_entstat (".", current_parsed_root->directory); 871#endif 872 } 873 874 875 /* Build dirs on the path if necessary and leave us in the 876 bottom directory (where if where was specified) doesn't 877 contain a CVS subdir yet, but all the others contain 878 CVS and Entries.Static files */ 879 880 if (build_dirs_and_chdir (head, argc <= 1) != 0) 881 { 882 error (0, 0, "ignoring module %s", omodule); 883 err = 1; 884 goto out; 885 } 886 } 887 888 /* set up the repository (or make sure the old one matches) */ 889 if (!isfile (CVSADM)) 890 { 891 FILE *fp; 892 893 if (!noexec && argc > 1) 894 { 895 /* I'm not sure whether this check is redundant. */ 896 if (!isdir (repository)) 897 error (1, 0, "there is no repository %s", repository); 898 899 Create_Admin (".", preload_update_dir, repository, 900 (char *) NULL, (char *) NULL, 0, 0, 901 m_type == CHECKOUT); 902 fp = open_file (CVSADM_ENTSTAT, "w+"); 903 if (fclose(fp) == EOF) 904 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 905#ifdef SERVER_SUPPORT 906 if (server_active) 907 server_set_entstat (where, repository); 908#endif 909 } 910 else 911 { 912 /* I'm not sure whether this check is redundant. */ 913 if (!isdir (repository)) 914 error (1, 0, "there is no repository %s", repository); 915 916 Create_Admin (".", preload_update_dir, repository, tag, date, 917 918 /* FIXME? This is a guess. If it is important 919 for nonbranch to be set correctly here I 920 think we need to write it one way now and 921 then rewrite it later via WriteTag, once 922 we've had a chance to call RCS_nodeisbranch 923 on each file. */ 924 0, 0, m_type == CHECKOUT); 925 } 926 } 927 else 928 { 929 char *repos; 930 931 if (m_type == EXPORT) 932 error (1, 0, "cannot export into working directory"); 933 934 /* get the contents of the previously existing repository */ 935 repos = Name_Repository ((char *) NULL, preload_update_dir); 936 if (fncmp (repository, repos) != 0) 937 { 938 error (0, 0, "existing repository %s does not match %s", 939 repos, repository); 940 error (0, 0, "ignoring module %s", omodule); 941 free (repos); 942 err = 1; 943 goto out; 944 } 945 free (repos); 946 } 947 } 948 949 /* 950 * If we are going to be updating to stdout, we need to cd to the 951 * repository directory so the recursion processor can use the current 952 * directory as the place to find repository information 953 */ 954 if (pipeout) 955 { 956 if ( CVS_CHDIR (repository) < 0) 957 { 958 error (0, errno, "cannot chdir to %s", repository); 959 err = 1; 960 goto out; 961 } 962 which = W_REPOS; 963 if (tag != NULL && !tag_validated) 964 { 965 tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, NULL); 966 tag_validated = 1; 967 } 968 } 969 else 970 { 971 which = W_LOCAL | W_REPOS; 972 if (tag != NULL && !tag_validated) 973 { 974 tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, 975 repository); 976 tag_validated = 1; 977 } 978 } 979 980 if (tag != NULL || date != NULL || join_rev1 != NULL) 981 which |= W_ATTIC; 982 983 if (! join_tags_validated) 984 { 985 if (join_rev1 != NULL) 986 tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag, 987 repository); 988 if (join_rev2 != NULL) 989 tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag, 990 repository); 991 join_tags_validated = 1; 992 } 993 994 /* 995 * if we are going to be recursive (building dirs), go ahead and call the 996 * update recursion processor. We will be recursive unless either local 997 * only was specified, or we were passed arguments 998 */ 999 if (!(local_specified || argc > 1)) 1000 { 1001 if (m_type == CHECKOUT && !pipeout) 1002 history_write ('O', preload_update_dir, history_name, where, 1003 repository); 1004 else if (m_type == EXPORT && !pipeout) 1005 history_write ('E', preload_update_dir, tag ? tag : date, where, 1006 repository); 1007 err += do_update (0, (char **) NULL, options, tag, date, 1008 force_tag_match, 0 /* !local */ , 1009 1 /* update -d */ , aflag, checkout_prune_dirs, 1010 pipeout, which, join_rev1, join_rev2, 1011 preload_update_dir, m_type == CHECKOUT); 1012 goto out; 1013 } 1014 1015 if (!pipeout) 1016 { 1017 int i; 1018 List *entries; 1019 1020 /* we are only doing files, so register them */ 1021 entries = Entries_Open (0, NULL); 1022 for (i = 1; i < argc; i++) 1023 { 1024 char *line; 1025 Vers_TS *vers; 1026 struct file_info finfo; 1027 1028 memset (&finfo, 0, sizeof finfo); 1029 finfo.file = argv[i]; 1030 /* Shouldn't be used, so set to arbitrary value. */ 1031 finfo.update_dir = NULL; 1032 finfo.fullname = argv[i]; 1033 finfo.repository = repository; 1034 finfo.entries = entries; 1035 /* The rcs slot is needed to get the options from the RCS 1036 file */ 1037 finfo.rcs = RCS_parse (finfo.file, repository); 1038 1039 vers = Version_TS (&finfo, options, tag, date, 1040 force_tag_match, 0); 1041 if (vers->ts_user == NULL) 1042 { 1043 line = xmalloc (strlen (finfo.file) + 15); 1044 (void) sprintf (line, "Initial %s", finfo.file); 1045 Register (entries, finfo.file, 1046 vers->vn_rcs ? vers->vn_rcs : "0", 1047 line, vers->options, vers->tag, 1048 vers->date, (char *) 0); 1049 free (line); 1050 } 1051 freevers_ts (&vers); 1052 freercsnode (&finfo.rcs); 1053 } 1054 1055 Entries_Close (entries); 1056 } 1057 1058 /* Don't log "export", just regular "checkouts" */ 1059 if (m_type == CHECKOUT && !pipeout) 1060 history_write ('O', preload_update_dir, history_name, where, 1061 repository); 1062 1063 /* go ahead and call update now that everything is set */ 1064 err += do_update (argc - 1, argv + 1, options, tag, date, 1065 force_tag_match, local_specified, 1 /* update -d */, 1066 aflag, checkout_prune_dirs, pipeout, which, join_rev1, 1067 join_rev2, preload_update_dir, m_type == CHECKOUT); 1068out: 1069 free (preload_update_dir); 1070 preload_update_dir = oldupdate; 1071 free (where); 1072 free (repository); 1073 return (err); 1074} 1075 1076static char * 1077findslash (start, p) 1078 char *start; 1079 char *p; 1080{ 1081 for (;;) 1082 { 1083 if (*p == '/') return p; 1084 if (p == start) break; 1085 --p; 1086 } 1087 return NULL; 1088} 1089 1090/* Return a newly malloc'd string containing a pathname for CVSNULLREPOS, 1091 and make sure that it exists. If there is an error creating the 1092 directory, give a fatal error. Otherwise, the directory is guaranteed 1093 to exist when we return. */ 1094char * 1095emptydir_name () 1096{ 1097 char *repository; 1098 1099 repository = xmalloc (strlen (current_parsed_root->directory) 1100 + sizeof (CVSROOTADM) 1101 + sizeof (CVSNULLREPOS) 1102 + 3); 1103 (void) sprintf (repository, "%s/%s/%s", current_parsed_root->directory, 1104 CVSROOTADM, CVSNULLREPOS); 1105 if (!isfile (repository)) 1106 { 1107 mode_t omask; 1108 omask = umask (cvsumask); 1109 if (CVS_MKDIR (repository, 0777) < 0) 1110 error (1, errno, "cannot create %s", repository); 1111 (void) umask (omask); 1112 } 1113 return repository; 1114} 1115 1116/* Build all the dirs along the path to DIRS with CVS subdirs with appropriate 1117 repositories. If ->repository is NULL, do not create a CVSADM directory 1118 for that subdirectory; just CVS_CHDIR into it. */ 1119static int 1120build_dirs_and_chdir (dirs, sticky) 1121 struct dir_to_build *dirs; 1122 int sticky; 1123{ 1124 int retval = 0; 1125 struct dir_to_build *nextdir; 1126 1127 while (dirs != NULL) 1128 { 1129 char *dir = last_component (dirs->dirpath); 1130 1131 if (!dirs->just_chdir) 1132 { 1133 mkdir_if_needed (dir); 1134 Subdir_Register (NULL, NULL, dir); 1135 } 1136 1137 if (CVS_CHDIR (dir) < 0) 1138 { 1139 error (0, errno, "cannot chdir to %s", dir); 1140 retval = 1; 1141 goto out; 1142 } 1143 if (dirs->repository != NULL) 1144 { 1145 build_one_dir (dirs->repository, dirs->dirpath, sticky); 1146 free (dirs->repository); 1147 } 1148 nextdir = dirs->next; 1149 free (dirs->dirpath); 1150 free (dirs); 1151 dirs = nextdir; 1152 } 1153 1154 out: 1155 while (dirs != NULL) 1156 { 1157 if (dirs->repository != NULL) 1158 free (dirs->repository); 1159 nextdir = dirs->next; 1160 free (dirs->dirpath); 1161 free (dirs); 1162 dirs = nextdir; 1163 } 1164 return retval; 1165} 1166