checkout.c revision 17721
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 build_dirs_and_chdir PROTO((char *dir, char *prepath, char *realdir, 40 int sticky)); 41static int checkout_proc PROTO((int *pargc, char **argv, char *where, 42 char *mwhere, char *mfile, int shorten, 43 int local_specified, char *omodule, 44 char *msg)); 45static int safe_location PROTO((void)); 46 47static const char *const checkout_usage[] = 48{ 49 "Usage:\n %s %s [-ANPcflnps] [-r rev | -D date] [-d dir] [-k kopt] modules...\n", 50 "\t-A\tReset any sticky tags/date/kopts.\n", 51 "\t-N\tDon't shorten module paths if -d specified.\n", 52 "\t-P\tPrune empty directories.\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.\n", 58 "\t-s\tLike -c, but include module status.\n", 59 "\t-r rev\tCheck out revision or tag. (implies -P)\n", 60 "\t-D date\tCheck out revisions as of date. (implies -P)\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 [-NPfln] [-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-n\tDo not run module program (if any).\n", 74 "\t-r rev\tCheck out revision or tag.\n", 75 "\t-D date\tCheck out revisions as of date.\n", 76 "\t-d dir\tCheck out into dir instead of module name.\n", 77 "\t-k kopt\tUse RCS kopt -k option on checkout.\n", 78 NULL 79}; 80 81static int checkout_prune_dirs; 82static int force_tag_match = 1; 83static int pipeout; 84static int aflag; 85static char *options = NULL; 86static char *tag = NULL; 87static int tag_validated = 0; 88static char *date = NULL; 89static char *join_rev1 = NULL; 90static char *join_rev2 = NULL; 91static char *preload_update_dir = NULL; 92 93int 94checkout (argc, argv) 95 int argc; 96 char **argv; 97{ 98 int i; 99 int c; 100 DBM *db; 101 int cat = 0, err = 0, status = 0; 102 int run_module_prog = 1; 103 int local = 0; 104 int shorten = -1; 105 char *where = NULL; 106 char *valid_options; 107 const char *const *valid_usage; 108 enum mtype m_type; 109 110 /* 111 * A smaller subset of options are allowed for the export command, which 112 * is essentially like checkout, except that it hard-codes certain 113 * options to be default (like -kv) and takes care to remove the CVS 114 * directory when it has done its duty 115 */ 116 if (strcmp (command_name, "export") == 0) 117 { 118 m_type = EXPORT; 119 valid_options = "Nnk:d:flRQqr:D:"; 120 valid_usage = export_usage; 121 } 122 else 123 { 124 m_type = CHECKOUT; 125 valid_options = "ANnk:d:flRpQqcsr:D:j:P"; 126 valid_usage = checkout_usage; 127 } 128 129 if (argc == -1) 130 usage (valid_usage); 131 132 ign_setup (); 133 wrap_setup (); 134 135 optind = 1; 136 while ((c = getopt (argc, argv, valid_options)) != -1) 137 { 138 switch (c) 139 { 140 case 'A': 141 aflag = 1; 142 break; 143 case 'N': 144 shorten = 0; 145 break; 146 case 'k': 147 if (options) 148 free (options); 149 options = RCS_check_kflag (optarg); 150 break; 151 case 'n': 152 run_module_prog = 0; 153 break; 154 case 'Q': 155 case 'q': 156#ifdef SERVER_SUPPORT 157 /* The CVS 1.5 client sends these options (in addition to 158 Global_option requests), so we must ignore them. */ 159 if (!server_active) 160#endif 161 error (1, 0, 162 "-q or -Q must be specified before \"%s\"", 163 command_name); 164 break; 165 case 'l': 166 local = 1; 167 break; 168 case 'R': 169 local = 0; 170 break; 171 case 'P': 172 checkout_prune_dirs = 1; 173 break; 174 case 'p': 175 pipeout = 1; 176 run_module_prog = 0; /* don't run module prog when piping */ 177 noexec = 1; /* so no locks will be created */ 178 break; 179 case 'c': 180 cat = 1; 181 break; 182 case 'd': 183 where = optarg; 184 if (shorten == -1) 185 shorten = 1; 186 break; 187 case 's': 188 status = 1; 189 break; 190 case 'f': 191 force_tag_match = 0; 192 break; 193 case 'r': 194 tag = optarg; 195 checkout_prune_dirs = 1; 196 break; 197 case 'D': 198 date = Make_Date (optarg); 199 checkout_prune_dirs = 1; 200 break; 201 case 'j': 202 if (join_rev2) 203 error (1, 0, "only two -j options can be specified"); 204 if (join_rev1) 205 join_rev2 = optarg; 206 else 207 join_rev1 = optarg; 208 break; 209 case '?': 210 default: 211 usage (valid_usage); 212 break; 213 } 214 } 215 argc -= optind; 216 argv += optind; 217 218 if (shorten == -1) 219 shorten = 0; 220 221 if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0) 222 || (tag && date)) 223 usage (valid_usage); 224 225 if (where && pipeout) 226 error (1, 0, "-d and -p are mutually exclusive"); 227 228 if (strcmp (command_name, "export") == 0) 229 { 230 if (!tag && !date) 231 { 232 error (0, 0, "must specify a tag or date"); 233 usage (valid_usage); 234 } 235 if (tag && isdigit (tag[0])) 236 error (1, 0, "tag `%s' must be a symbolic tag", tag); 237/* 238 * mhy 950615: -kv doesn't work for binaries with RCS keywords. 239 * Instead use the default provided in the RCS file (-ko for binaries). 240 */ 241#if 0 242 if (!options) 243 options = RCS_check_kflag ("v");/* -kv is default */ 244#endif 245 } 246 247 if (!safe_location()) { 248 error(1, 0, "Cannot check out files into the repository itself"); 249 } 250 251#ifdef CLIENT_SUPPORT 252 if (client_active) 253 { 254 int expand_modules; 255 256 start_server (); 257 258 ign_setup (); 259 260 /* We have to expand names here because the "expand-modules" 261 directive to the server has the side-effect of having the 262 server send the check-in and update programs for the 263 various modules/dirs requested. If we turn this off and 264 simply request the names of the modules and directories (as 265 below in !expand_modules), those files (CVS/Checking.prog 266 or CVS/Update.prog) don't get created. Grrr. */ 267 268 expand_modules = (!cat && !status && !pipeout 269 && supported_request ("expand-modules")); 270 271 if (expand_modules) 272 { 273 /* This is done here because we need to read responses 274 from the server before we send the command checkout or 275 export files. */ 276 277 client_expand_modules (argc, argv, local); 278 } 279 280 if (!run_module_prog) send_arg ("-n"); 281 if (local) send_arg ("-l"); 282 if (pipeout) send_arg ("-p"); 283 if (!force_tag_match) send_arg ("-f"); 284 if (aflag) 285 send_arg("-A"); 286 if (!shorten) 287 send_arg("-N"); 288 if (checkout_prune_dirs && strcmp (command_name, "export") != 0) 289 send_arg("-P"); 290 client_prune_dirs = checkout_prune_dirs; 291 if (cat) 292 send_arg("-c"); 293 if (where != NULL) 294 { 295 option_with_arg ("-d", where); 296 } 297 if (status) 298 send_arg("-s"); 299 if (strcmp (command_name, "export") != 0 300 && options != NULL 301 && options[0] != '\0') 302 send_arg (options); 303 option_with_arg ("-r", tag); 304 if (date) 305 client_senddate (date); 306 if (join_rev1 != NULL) 307 option_with_arg ("-j", join_rev1); 308 if (join_rev2 != NULL) 309 option_with_arg ("-j", join_rev2); 310 311 if (expand_modules) 312 { 313 client_send_expansions (local); 314 } 315 else 316 { 317 int i; 318 for (i = 0; i < argc; ++i) 319 send_arg (argv[i]); 320 client_nonexpanded_setup (); 321 } 322 323 send_to_server (strcmp (command_name, "export") == 0 ? 324 "export\012" : "co\012", 325 0); 326 327 return get_responses_and_close (); 328 } 329#endif /* CLIENT_SUPPORT */ 330 331 if (cat || status) 332 { 333 cat_module (status); 334 return (0); 335 } 336 db = open_module (); 337 338 /* 339 * if we have more than one argument and where was specified, we make the 340 * where, cd into it, and try to shorten names as much as possible. 341 * Otherwise, we pass the where as a single argument to do_module. 342 */ 343 if (argc > 1 && where != NULL) 344 { 345 char repository[PATH_MAX]; 346 347 (void) CVS_MKDIR (where, 0777); 348 if (chdir (where) < 0) 349 error (1, errno, "cannot chdir to %s", where); 350 preload_update_dir = xstrdup (where); 351 where = (char *) NULL; 352 if (!isfile (CVSADM)) 353 { 354 (void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM, 355 CVSNULLREPOS); 356 if (!isfile (repository)) 357 { 358 mode_t omask; 359 omask = umask (cvsumask); 360 (void) CVS_MKDIR (repository, 0777); 361 (void) umask (omask); 362 } 363 364 /* I'm not sure whether this check is redundant. */ 365 if (!isdir (repository)) 366 error (1, 0, "there is no repository %s", repository); 367 368 Create_Admin (".", where, repository, 369 (char *) NULL, (char *) NULL); 370 if (!noexec) 371 { 372 FILE *fp; 373 374 fp = open_file (CVSADM_ENTSTAT, "w+"); 375 if (fclose(fp) == EOF) 376 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 377#ifdef SERVER_SUPPORT 378 if (server_active) 379 server_set_entstat (preload_update_dir, repository); 380#endif 381 } 382 } 383 } 384 385 /* 386 * if where was specified (-d) and we have not taken care of it already 387 * with the multiple arg stuff, and it was not a simple directory name 388 * but rather a path, we strip off everything but the last component and 389 * attempt to cd to the indicated place. where then becomes simply the 390 * last component 391 */ 392 if (where != NULL && strchr (where, '/') != NULL) 393 { 394 char *slash; 395 396 slash = strrchr (where, '/'); 397 *slash = '\0'; 398 399 if (chdir (where) < 0) 400 error (1, errno, "cannot chdir to %s", where); 401 402 preload_update_dir = xstrdup (where); 403 404 where = slash + 1; 405 if (*where == '\0') 406 where = NULL; 407 } 408 409 for (i = 0; i < argc; i++) 410 err += do_module (db, argv[i], m_type, "Updating", checkout_proc, 411 where, shorten, local, run_module_prog, 412 (char *) NULL); 413 close_module (db); 414 return (err); 415} 416 417static int 418safe_location () 419{ 420 char current[PATH_MAX]; 421 char hardpath[PATH_MAX+5]; 422 int x; 423 424 x = readlink(CVSroot, hardpath, sizeof hardpath - 1); 425 if (x == -1) 426 { 427 strcpy(hardpath, CVSroot); 428 } 429 else 430 { 431 hardpath[x] = '\0'; 432 } 433 getwd (current); 434 if (strncmp(current, hardpath, strlen(hardpath)) == 0) 435 { 436 return (0); 437 } 438 return (1); 439} 440 441/* 442 * process_module calls us back here so we do the actual checkout stuff 443 */ 444/* ARGSUSED */ 445static int 446checkout_proc (pargc, argv, where, mwhere, mfile, shorten, 447 local_specified, omodule, msg) 448 int *pargc; 449 char **argv; 450 char *where; 451 char *mwhere; 452 char *mfile; 453 int shorten; 454 int local_specified; 455 char *omodule; 456 char *msg; 457{ 458 int err = 0; 459 int which; 460 char *cp; 461 char *cp2; 462 char repository[PATH_MAX]; 463 char xwhere[PATH_MAX]; 464 char *oldupdate = NULL; 465 char *prepath; 466 char *realdirs; 467 468 /* 469 * OK, so we're doing the checkout! Our args are as follows: 470 * argc,argv contain either dir or dir followed by a list of files 471 * where contains where to put it (if supplied by checkout) 472 * mwhere contains the module name or -d from module file 473 * mfile says do only that part of the module 474 * shorten = TRUE says shorten as much as possible 475 * omodule is the original arg to do_module() 476 */ 477 478 /* set up the repository (maybe) for the bottom directory */ 479 (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); 480 481 /* save the original value of preload_update_dir */ 482 if (preload_update_dir != NULL) 483 oldupdate = xstrdup (preload_update_dir); 484 485 /* fix up argv[] for the case of partial modules */ 486 if (mfile != NULL) 487 { 488 char file[PATH_MAX]; 489 490 /* if mfile is really a path, straighten it out first */ 491 if ((cp = strrchr (mfile, '/')) != NULL) 492 { 493 *cp = 0; 494 (void) strcat (repository, "/"); 495 (void) strcat (repository, mfile); 496 497 /* 498 * Now we need to fill in the where correctly. if !shorten, tack 499 * the rest of the path onto where if where is filled in 500 * otherwise tack the rest of the path onto mwhere and make that 501 * the where 502 * 503 * If shorten is enabled, we might use mwhere to set where if 504 * nobody set it yet, so we'll need to setup mwhere as the last 505 * component of the path we are tacking onto repository 506 */ 507 if (!shorten) 508 { 509 if (where != NULL) 510 (void) sprintf (xwhere, "%s/%s", where, mfile); 511 else 512 (void) sprintf (xwhere, "%s/%s", mwhere, mfile); 513 where = xwhere; 514 } 515 else 516 { 517 char *slash; 518 519 if ((slash = strrchr (mfile, '/')) != NULL) 520 mwhere = slash + 1; 521 else 522 mwhere = mfile; 523 } 524 mfile = cp + 1; 525 } 526 527 (void) sprintf (file, "%s/%s", repository, mfile); 528 if (isdir (file)) 529 { 530 531 /* 532 * The portion of a module was a directory, so kludge up where to 533 * be the subdir, and fix up repository 534 */ 535 (void) strcpy (repository, file); 536 537 /* 538 * At this point, if shorten is not enabled, we make where either 539 * where with mfile concatenated, or if where hadn't been set we 540 * set it to mwhere with mfile concatenated. 541 * 542 * If shorten is enabled and where hasn't been set yet, then where 543 * becomes mfile 544 */ 545 if (!shorten) 546 { 547 if (where != NULL) 548 (void) sprintf (xwhere, "%s/%s", where, mfile); 549 else 550 (void) sprintf (xwhere, "%s/%s", mwhere, mfile); 551 where = xwhere; 552 } 553 else if (where == NULL) 554 where = mfile; 555 } 556 else 557 { 558 int i; 559 560 /* 561 * The portion of a module was a file, so kludge up argv to be 562 * correct 563 */ 564 for (i = 1; i < *pargc; i++)/* free the old ones */ 565 free (argv[i]); 566 argv[1] = xstrdup (mfile); /* set up the new one */ 567 *pargc = 2; 568 569 /* where gets mwhere if where isn't set */ 570 if (where == NULL) 571 where = mwhere; 572 } 573 } 574 575 /* 576 * if shorten is enabled and where isn't specified yet, we pluck the last 577 * directory component of argv[0] and make it the where 578 */ 579 if (shorten && where == NULL) 580 { 581 if ((cp = strrchr (argv[0], '/')) != NULL) 582 { 583 (void) strcpy (xwhere, cp + 1); 584 where = xwhere; 585 } 586 } 587 588 /* if where is still NULL, use mwhere if set or the argv[0] dir */ 589 if (where == NULL) 590 { 591 if (mwhere) 592 where = mwhere; 593 else 594 { 595 (void) strcpy (xwhere, argv[0]); 596 where = xwhere; 597 } 598 } 599 600 if (preload_update_dir != NULL) 601 { 602 char tmp[PATH_MAX]; 603 604 (void) sprintf (tmp, "%s/%s", preload_update_dir, where); 605 free (preload_update_dir); 606 preload_update_dir = xstrdup (tmp); 607 } 608 else 609 preload_update_dir = xstrdup (where); 610 611 /* 612 * At this point, where is the directory we want to build, repository is 613 * the repository for the lowest level of the path. 614 */ 615 616 /* 617 * If we are sending everything to stdout, we can skip a whole bunch of 618 * work from here 619 */ 620 if (!pipeout) 621 { 622 623 /* 624 * We need to tell build_dirs not only the path we want it to build, 625 * but also the repositories we want it to populate the path with. To 626 * accomplish this, we pass build_dirs a ``real path'' with valid 627 * repositories and a string to pre-pend based on how many path 628 * elements exist in where. Big Black Magic 629 */ 630 prepath = xstrdup (repository); 631 cp = strrchr (where, '/'); 632 cp2 = strrchr (prepath, '/'); 633 while (cp != NULL) 634 { 635 cp = findslash (where, cp - 1); 636 cp2 = findslash (prepath, cp2 - 1); 637 } 638 *cp2 = '\0'; 639 realdirs = cp2 + 1; 640 641 /* 642 * build dirs on the path if necessary and leave us in the bottom 643 * directory (where if where was specified) doesn't contain a CVS 644 * subdir yet, but all the others contain CVS and Entries.Static 645 * files 646 */ 647 if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0) 648 { 649 error (0, 0, "ignoring module %s", omodule); 650 free (prepath); 651 free (preload_update_dir); 652 preload_update_dir = oldupdate; 653 return (1); 654 } 655 656 /* clean up */ 657 free (prepath); 658 659 /* set up the repository (or make sure the old one matches) */ 660 if (!isfile (CVSADM)) 661 { 662 FILE *fp; 663 664 if (!noexec && *pargc > 1) 665 { 666 /* I'm not sure whether this check is redundant. */ 667 if (!isdir (repository)) 668 error (1, 0, "there is no repository %s", repository); 669 670 Create_Admin (".", where, repository, 671 (char *) NULL, (char *) NULL); 672 fp = open_file (CVSADM_ENTSTAT, "w+"); 673 if (fclose(fp) == EOF) 674 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 675#ifdef SERVER_SUPPORT 676 if (server_active) 677 server_set_entstat (where, repository); 678#endif 679 } 680 else 681 { 682 /* I'm not sure whether this check is redundant. */ 683 if (!isdir (repository)) 684 error (1, 0, "there is no repository %s", repository); 685 686 Create_Admin (".", where, repository, tag, date); 687 } 688 } 689 else 690 { 691 char *repos; 692 693 /* get the contents of the previously existing repository */ 694 repos = Name_Repository ((char *) NULL, preload_update_dir); 695 if (fncmp (repository, repos) != 0) 696 { 697 error (0, 0, "existing repository %s does not match %s", 698 repos, repository); 699 error (0, 0, "ignoring module %s", omodule); 700 free (repos); 701 free (preload_update_dir); 702 preload_update_dir = oldupdate; 703 return (1); 704 } 705 free (repos); 706 } 707 } 708 709 /* 710 * If we are going to be updating to stdout, we need to cd to the 711 * repository directory so the recursion processor can use the current 712 * directory as the place to find repository information 713 */ 714 if (pipeout) 715 { 716 if (chdir (repository) < 0) 717 { 718 error (0, errno, "cannot chdir to %s", repository); 719 free (preload_update_dir); 720 preload_update_dir = oldupdate; 721 return (1); 722 } 723 which = W_REPOS; 724 if (tag != NULL && !tag_validated) 725 { 726 tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL); 727 tag_validated = 1; 728 } 729 } 730 else 731 { 732 which = W_LOCAL | W_REPOS; 733 if (tag != NULL && !tag_validated) 734 { 735 tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, 736 repository); 737 tag_validated = 1; 738 } 739 } 740 741 if (tag != NULL || date != NULL) 742 which |= W_ATTIC; 743 744 /* FIXME: We don't call tag_check_valid on join_rev1 and join_rev2 745 yet (make sure to handle ':' correctly if we do, though). */ 746 747 /* 748 * if we are going to be recursive (building dirs), go ahead and call the 749 * update recursion processor. We will be recursive unless either local 750 * only was specified, or we were passed arguments 751 */ 752 if (!(local_specified || *pargc > 1)) 753 { 754 if (strcmp (command_name, "export") != 0 && !pipeout) 755 history_write ('O', preload_update_dir, tag ? tag : date, where, 756 repository); 757 err += do_update (0, (char **) NULL, options, tag, date, 758 force_tag_match, 0 /* !local */ , 759 1 /* update -d */ , aflag, checkout_prune_dirs, 760 pipeout, which, join_rev1, join_rev2, 761 preload_update_dir); 762 free (preload_update_dir); 763 preload_update_dir = oldupdate; 764 return (err); 765 } 766 767 if (!pipeout) 768 { 769 int i; 770 List *entries; 771 772 /* we are only doing files, so register them */ 773 entries = Entries_Open (0); 774 for (i = 1; i < *pargc; i++) 775 { 776 char *line; 777 char *user; 778 Vers_TS *vers; 779 780 user = argv[i]; 781 vers = Version_TS (repository, options, tag, date, user, 782 force_tag_match, 0, entries, (RCSNode *) NULL); 783 if (vers->ts_user == NULL) 784 { 785 line = xmalloc (strlen (user) + 15); 786 (void) sprintf (line, "Initial %s", user); 787 Register (entries, user, vers->vn_rcs ? vers->vn_rcs : "0", 788 line, vers->options, vers->tag, 789 vers->date, (char *) 0); 790 free (line); 791 } 792 freevers_ts (&vers); 793 } 794 795 Entries_Close (entries); 796 } 797 798 /* Don't log "export", just regular "checkouts" */ 799 if (strcmp (command_name, "export") != 0 && !pipeout) 800 history_write ('O', preload_update_dir, (tag ? tag : date), where, 801 repository); 802 803 /* go ahead and call update now that everything is set */ 804 err += do_update (*pargc - 1, argv + 1, options, tag, date, 805 force_tag_match, local_specified, 1 /* update -d */, 806 aflag, checkout_prune_dirs, pipeout, which, join_rev1, 807 join_rev2, preload_update_dir); 808 free (preload_update_dir); 809 preload_update_dir = oldupdate; 810 return (err); 811} 812 813static char * 814findslash (start, p) 815 char *start; 816 char *p; 817{ 818 while (p >= start && *p != '/') 819 p--; 820 if (p < start) 821 return (NULL); 822 else 823 return (p); 824} 825 826/* 827 * build all the dirs along the path to dir with CVS subdirs with appropriate 828 * repositories and Entries.Static files 829 */ 830static int 831build_dirs_and_chdir (dir, prepath, realdir, sticky) 832 char *dir; 833 char *prepath; 834 char *realdir; 835 int sticky; 836{ 837 FILE *fp; 838 char repository[PATH_MAX]; 839 char path[PATH_MAX]; 840 char path2[PATH_MAX]; 841 char *slash; 842 char *slash2; 843 char *cp; 844 char *cp2; 845 846 (void) strcpy (path, dir); 847 (void) strcpy (path2, realdir); 848 for (cp = path, cp2 = path2; 849 (slash = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL; 850 cp = slash + 1, cp2 = slash2 + 1) 851 { 852 *slash = '\0'; 853 *slash2 = '\0'; 854 (void) CVS_MKDIR (cp, 0777); 855 if (chdir (cp) < 0) 856 { 857 error (0, errno, "cannot chdir to %s", cp); 858 return (1); 859 } 860 if (!isfile (CVSADM) && strcmp (command_name, "export") != 0) 861 { 862 (void) sprintf (repository, "%s/%s", prepath, path2); 863 /* I'm not sure whether this check is redundant. */ 864 if (!isdir (repository)) 865 error (1, 0, "there is no repository %s", repository); 866 Create_Admin (".", path, repository, sticky ? (char *) NULL : tag, 867 sticky ? (char *) NULL : date); 868 if (!noexec) 869 { 870 fp = open_file (CVSADM_ENTSTAT, "w+"); 871 if (fclose(fp) == EOF) 872 error(1, errno, "cannot close %s", CVSADM_ENTSTAT); 873#ifdef SERVER_SUPPORT 874 if (server_active) 875 server_set_entstat (path, repository); 876#endif 877 } 878 } 879 *slash = '/'; 880 *slash2 = '/'; 881 } 882 (void) CVS_MKDIR (cp, 0777); 883 if (chdir (cp) < 0) 884 { 885 error (0, errno, "cannot chdir to %s", cp); 886 return (1); 887 } 888 return (0); 889} 890