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