]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/checkout.c
This commit was generated by cvs2svn to compensate for changes in r171827,
[FreeBSD/FreeBSD.git] / contrib / cvs / src / checkout.c
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 source distribution.
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 /*
37  * $FreeBSD$
38  */
39
40 #include <assert.h>
41 #include "cvs.h"
42
43 static char *findslash PROTO((char *start, char *p));
44 static int checkout_proc PROTO((int argc, char **argv, char *where,
45                           char *mwhere, char *mfile, int shorten,
46                           int local_specified, char *omodule,
47                           char *msg));
48
49 static const char *const checkout_usage[] =
50 {
51     "Usage:\n  %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n",
52     "    [-j rev1] [-j rev2] [-k kopt] modules...\n",
53     "\t-A\tReset any sticky tags/date/kopts.\n",
54     "\t-N\tDon't shorten module paths if -d specified.\n",
55     "\t-P\tPrune empty directories.\n",
56     "\t-R\tProcess directories recursively.\n",
57     "\t-T\tCreate Template file from local repository for remote commit.\n",
58     "\t-c\t\"cat\" the module database.\n",
59     "\t-f\tForce a head revision match if tag/date not found.\n",
60     "\t-l\tLocal directory only, not recursive\n",
61     "\t-n\tDo not run module program (if any).\n",
62     "\t-p\tCheck out files to standard output (avoids stickiness).\n",
63     "\t-s\tLike -c, but include module status.\n",
64     "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n",
65     "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n",
66     "\t-d dir\tCheck out into dir instead of module name.\n",
67     "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
68     "\t-j rev\tMerge in changes made between current revision and rev.\n",
69     "(Specify the --help global option for a list of other help options)\n",
70     NULL
71 };
72
73 static const char *const export_usage[] =
74 {
75     "Usage: %s %s [-NRfln] [-r rev] [-D date] [-d dir] [-k kopt] module...\n",
76     "\t-N\tDon't shorten module paths if -d specified.\n",
77     "\t-f\tForce a head revision match if tag/date not found.\n",
78     "\t-l\tLocal directory only, not recursive\n",
79     "\t-R\tProcess directories recursively (default).\n",
80     "\t-n\tDo not run module program (if any).\n",
81     "\t-r rev\tExport revision or tag.\n",
82     "\t-D date\tExport revisions as of date.\n",
83     "\t-d dir\tExport into dir instead of module name.\n",
84     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
85     "(Specify the --help global option for a list of other help options)\n",
86     NULL
87 };
88
89 static int checkout_prune_dirs;
90 static int force_tag_match;
91 static int pipeout;
92 static int aflag;
93 static char *options;
94 static char *tag;
95 static int tag_validated;
96 static char *date;
97 static char *join_rev1;
98 static char *join_rev2;
99 static int join_tags_validated;
100 static int pull_template;
101 static char *preload_update_dir;
102 static char *history_name;
103 static enum mtype m_type;
104
105 int
106 checkout (argc, argv)
107     int argc;
108     char **argv;
109 {
110     int i;
111     int c;
112     DBM *db;
113     int cat = 0, err = 0, status = 0;
114     int run_module_prog = 1;
115     int local = 0;
116     int shorten = -1;
117     char *where = NULL;
118     char *valid_options;
119     const char *const *valid_usage;
120
121     /* initialize static options */
122     force_tag_match = 1;
123     if (options)
124     {
125         free (options);
126         options = NULL;
127     }
128     tag = date = join_rev1 = join_rev2 = preload_update_dir = NULL;
129     history_name = NULL;
130     tag_validated = join_tags_validated = 0;
131
132
133     /*
134      * A smaller subset of options are allowed for the export command, which
135      * is essentially like checkout, except that it hard-codes certain
136      * options to be default (like -kv) and takes care to remove the CVS
137      * directory when it has done its duty
138      */
139     if (strcmp (cvs_cmd_name, "export") == 0)
140     {
141         m_type = EXPORT;
142         valid_options = "+Nnk:d:flRQqr:D:";
143         valid_usage = export_usage;
144     }
145     else
146     {
147         m_type = CHECKOUT;
148         valid_options = "+ANnk:d:flRpTQqcsr:D:j:P";
149         valid_usage = checkout_usage;
150     }
151
152     if (argc == -1)
153         usage (valid_usage);
154
155     ign_setup ();
156     wrap_setup ();
157
158     optind = 0;
159     while ((c = getopt (argc, argv, valid_options)) != -1)
160     {
161         switch (c)
162         {
163             case 'A':
164                 aflag = 1;
165                 break;
166             case 'N':
167                 shorten = 0;
168                 break;
169             case 'k':
170                 if (options)
171                     free (options);
172                 options = RCS_check_kflag (optarg);
173                 break;
174             case 'n':
175                 run_module_prog = 0;
176                 break;
177             case 'T':
178                 pull_template = 1;
179                 break;
180             case 'Q':
181             case 'q':
182 #ifdef SERVER_SUPPORT
183                 /* The CVS 1.5 client sends these options (in addition to
184                    Global_option requests), so we must ignore them.  */
185                 if (!server_active)
186 #endif
187                     error (1, 0,
188                            "-q or -Q must be specified before \"%s\"",
189                            cvs_cmd_name);
190                 break;
191             case 'l':
192                 local = 1;
193                 break;
194             case 'R':
195                 local = 0;
196                 break;
197             case 'P':
198                 checkout_prune_dirs = 1;
199                 break;
200             case 'p':
201                 pipeout = 1;
202                 run_module_prog = 0;    /* don't run module prog when piping */
203                 noexec = 1;             /* so no locks will be created */
204                 break;
205             case 'c':
206                 cat = 1;
207                 break;
208             case 'd':
209                 where = optarg;
210                 if (shorten == -1)
211                     shorten = 1;
212                 break;
213             case 's':
214                 cat = status = 1;
215                 break;
216             case 'f':
217                 force_tag_match = 0;
218                 break;
219             case 'r':
220                 tag = optarg;
221                 checkout_prune_dirs = 1;
222                 break;
223             case 'D':
224                 date = Make_Date (optarg);
225                 checkout_prune_dirs = 1;
226                 break;
227             case 'j':
228                 if (join_rev2)
229                     error (1, 0, "only two -j options can be specified");
230                 if (join_rev1)
231                     join_rev2 = optarg;
232                 else
233                     join_rev1 = optarg;
234                 break;
235             case '?':
236             default:
237                 usage (valid_usage);
238                 break;
239         }
240     }
241     argc -= optind;
242     argv += optind;
243
244     if (shorten == -1)
245         shorten = 0;
246
247     if (cat && argc != 0)
248         error (1, 0, "-c and -s must not get any arguments");
249
250     if (!cat && argc == 0)
251         error (1, 0, "must specify at least one module or directory");
252
253     if (where && pipeout)
254         error (1, 0, "-d and -p are mutually exclusive");
255
256     if (m_type == EXPORT)
257     {
258         if (!tag && !date)
259             error (1, 0, "must specify a tag or date");
260
261         if (tag && isdigit ((unsigned char) tag[0]))
262             error (1, 0, "tag `%s' must be a symbolic tag", tag);
263     }
264
265 #ifdef SERVER_SUPPORT
266     if (server_active && where != NULL)
267     {
268         server_pathname_check (where);
269     }
270 #endif
271
272     if (!cat && !pipeout && !safe_location( where )) {
273         error(1, 0, "Cannot check out files into the repository itself");
274     }
275
276 #ifdef CLIENT_SUPPORT
277     if (current_parsed_root->isremote)
278     {
279         int expand_modules;
280
281         start_server ();
282
283         ign_setup ();
284         
285         expand_modules = (!cat && !pipeout
286                           && supported_request ("expand-modules"));
287         
288         if (expand_modules)
289         {
290             /* This is done here because we need to read responses
291                from the server before we send the command checkout or
292                export files. */
293
294             client_expand_modules (argc, argv, local);
295         }
296
297         if (!run_module_prog)
298             send_arg ("-n");
299         if (local)
300             send_arg ("-l");
301         if (pipeout)
302             send_arg ("-p");
303         if (!force_tag_match)
304             send_arg ("-f");
305         if (aflag)
306             send_arg("-A");
307         if (!shorten)
308             send_arg("-N");
309         if (checkout_prune_dirs && m_type == CHECKOUT)
310             send_arg("-P");
311         client_prune_dirs = checkout_prune_dirs;
312         if (cat && !status)
313             send_arg("-c");
314         if (where != NULL)
315             option_with_arg ("-d", where);
316         if (status)
317             send_arg("-s");
318         if (options != NULL && options[0] != '\0')
319             send_arg (options);
320         option_with_arg ("-r", tag);
321         if (date)
322             client_senddate (date);
323         if (join_rev1 != NULL)
324             option_with_arg ("-j", join_rev1);
325         if (join_rev2 != NULL)
326             option_with_arg ("-j", join_rev2);
327         send_arg ("--");
328
329         if (expand_modules)
330         {
331             client_send_expansions (local, where, 1);
332         }
333         else
334         {
335             int i;
336             for (i = 0; i < argc; ++i)
337                 send_arg (argv[i]);
338             client_nonexpanded_setup ();
339         }
340
341         send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0);
342         return get_responses_and_close ();
343     }
344 #endif /* CLIENT_SUPPORT */
345
346     if (cat)
347     {
348         cat_module (status);
349         if (options)
350         {
351             free (options);
352             options = NULL;
353         }
354         return (0);
355     }
356     db = open_module ();
357
358
359     /* If we've specified something like "cvs co foo/bar baz/quux"
360        don't try to shorten names.  There are a few cases in which we
361        could shorten (e.g. "cvs co foo/bar foo/baz"), but we don't
362        handle those yet.  Better to have an extra directory created
363        than the thing checked out under the wrong directory name. */
364
365     if (argc > 1)
366         shorten = 0;
367
368
369     /* If we will be calling history_write, work out the name to pass
370        it.  */
371     if (!pipeout)
372     {
373         if (!date)
374             history_name = tag;
375         else if (!tag)
376             history_name = date;
377         else
378         {
379             history_name = xmalloc (strlen (tag) + strlen (date) + 2);
380             sprintf (history_name, "%s:%s", tag, date);
381         }
382     }
383
384
385     for (i = 0; i < argc; i++)
386         err += do_module (db, argv[i], m_type, "Updating", checkout_proc,
387                           where, shorten, local, run_module_prog, !pipeout,
388                           (char *) NULL);
389     close_module (db);
390     if (options)
391     {
392         free (options);
393         options = NULL;
394     }
395     if (history_name != tag && history_name != date && history_name != NULL)
396         free (history_name);
397     return (err);
398 }
399
400 /* FIXME: This is and emptydir_name are in checkout.c for historical
401    reasons, probably want to move them.  */
402
403 /* int
404  * safe_location ( char *where )
405  *
406  * Return true if where is a safe destination for a checkout.
407  *
408  * INPUTS
409  *  where       The requested destination directory.
410  *
411  * GLOBALS
412  *  current_parsed_root->directory
413  *  current_parsed_root->isremote
414  *              Used to locate our CVSROOT.
415  *
416  * RETURNS
417  *  true        If we are running in client mode or if where is not located
418  *              within the CVSROOT.
419  *  false       Otherwise.
420  *
421  * ERRORS
422  *  Exits with a fatal error message when various events occur, such as not
423  *  being able to resolve a path or failing ot chdir to a path.
424  */
425 int
426 safe_location (where)
427     char *where;
428 {
429     char *current;
430     char *where_location;
431     char *hardpath;
432     size_t hardpath_len;
433     int retval;
434
435     if (trace)
436         (void) fprintf (stderr, "%s-> safe_location( where=%s )\n",
437                         CLIENT_SERVER_STR,
438                         where ? where : "(null)");
439
440 #ifdef CLIENT_SUPPORT
441     /* Don't compare remote CVSROOTs to our destination directory. */
442     if ( current_parsed_root->isremote ) return 1;
443 #endif /* CLIENT_SUPPORT */
444
445     /* set current - even if where is set we'll need to cd back... */
446     current = xgetwd ();
447     if (current == NULL)
448         error (1, errno, "could not get working directory");
449
450     hardpath = xresolvepath ( current_parsed_root->directory );
451
452     /* if where is set, set current to where, where - last_component( where ),
453      * or fail, depending on whether the directories exist or not.
454      */
455     if( where != NULL )
456     {
457         if( chdir( where ) != -1 )
458         {
459             /* where */
460             where_location = xgetwd();
461             if( where_location == NULL )
462                 error( 1, errno, "could not get working directory" );
463
464             if( chdir( current ) == -1 )
465                 error( 1, errno, "could not change directory to `%s'", current );
466
467             free( current );
468             current = where_location;
469         }
470         else if( errno == ENOENT )
471         {
472             if ( last_component( where ) != where )
473             {
474                 /* where - last_component( where ) */
475                 char *parent;
476
477                 /* strip the last_component */
478                 where_location = xstrdup (where);
479                 /* It's okay to cast out the const below since we know we just
480                  * allocated where_location and can do what we like with it.
481                  */
482                 parent = (char *)last_component (where_location);
483                 parent[-1] = '\0';
484
485                 if( chdir( where_location ) != -1 )
486                 {
487                     free( where_location );
488                     where_location = xgetwd();
489                     if( where_location == NULL )
490                         error( 1, errno, "could not get working directory (nominally `%s')", where_location );
491
492                     if( chdir( current ) == -1 )
493                         error( 1, errno, "could not change directory to `%s'", current );
494
495                     free( current );
496                     current = where_location;
497                 }
498                 else
499                     /* fail */
500                     error( 1, errno, "could not change directory to requested checkout directory `%s'", where_location );
501             }
502             /* else: ERRNO == ENOENT & last_component(where) == where
503              * for example, 'cvs co -d newdir module', where newdir hasn't
504              * been created yet, so leave current set to '.' and check that
505              */
506         }
507         else
508             /* fail */
509             error( 1, errno, "could not change directory to requested checkout directory `%s'", where );
510     }
511
512     hardpath_len = strlen (hardpath);
513     if (strlen (current) >= hardpath_len
514         && strncmp (current, hardpath, hardpath_len) == 0)
515     {
516         if (/* Current is a subdirectory of hardpath.  */
517             current[hardpath_len] == '/'
518
519             /* Current is hardpath itself.  */
520             || current[hardpath_len] == '\0')
521             retval = 0;
522         else
523             /* It isn't a problem.  For example, current is
524                "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot".  */
525             retval = 1;
526     }
527     else
528         retval = 1;
529     free (current);
530     free (hardpath);
531     return retval;
532 }
533
534 struct dir_to_build
535 {
536     /* What to put in CVS/Repository.  */
537     char *repository;
538     /* The path to the directory.  */
539     char *dirpath;
540
541     /* If set, don't build the directory, just change to it.
542        The caller will also want to set REPOSITORY to NULL.  */
543     int just_chdir;
544
545     struct dir_to_build *next;
546 };
547
548 static int build_dirs_and_chdir PROTO ((struct dir_to_build *list,
549                                         int sticky));
550
551 static void build_one_dir PROTO ((char *, char *, int));
552
553 static void
554 build_one_dir (repository, dirpath, sticky)
555     char *repository;
556     char *dirpath;
557     int sticky;
558 {
559     FILE *fp;
560
561     if (isfile (CVSADM))
562     {
563         if (m_type == EXPORT)
564             error (1, 0, "cannot export into a working directory");
565     }
566     else if (m_type == CHECKOUT)
567     {
568         /* I suspect that this check could be omitted.  */
569         if (!isdir (repository))
570             error (1, 0, "there is no repository %s", repository);
571
572         if (Create_Admin (".", dirpath, repository,
573                           sticky ? tag : (char *) NULL,
574                           sticky ? date : (char *) NULL,
575
576                           /* FIXME?  This is a guess.  If it is important
577                              for nonbranch to be set correctly here I
578                              think we need to write it one way now and
579                              then rewrite it later via WriteTag, once
580                              we've had a chance to call RCS_nodeisbranch
581                              on each file.  */
582                           0, 1, 1))
583             return;
584
585         if (!noexec)
586         {
587             fp = open_file (CVSADM_ENTSTAT, "w+");
588             if (fclose (fp) == EOF)
589                 error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
590 #ifdef SERVER_SUPPORT
591             if (server_active)
592                 server_set_entstat (dirpath, repository);
593 #endif
594         }
595     }
596 }
597
598 /*
599  * process_module calls us back here so we do the actual checkout stuff
600  */
601 /* ARGSUSED */
602 static int
603 checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten,
604                local_specified, omodule, msg)
605     int argc;
606     char **argv;
607     char *where_orig;
608     char *mwhere;
609     char *mfile;
610     int shorten;
611     int local_specified;
612     char *omodule;
613     char *msg;
614 {
615     char *myargv[2];
616     int err = 0;
617     int which;
618     char *cp;
619     char *repository;
620     char *oldupdate = NULL;
621     char *where;
622
623     /*
624      * OK, so we're doing the checkout! Our args are as follows: 
625      *  argc,argv contain either dir or dir followed by a list of files 
626      *  where contains where to put it (if supplied by checkout) 
627      *  mwhere contains the module name or -d from module file 
628      *  mfile says do only that part of the module
629      *  shorten = 1 says shorten as much as possible 
630      *  omodule is the original arg to do_module()
631      */
632
633     /* Set up the repository (maybe) for the bottom directory.
634        Allocate more space than we need so we don't need to keep
635        reallocating this string. */
636     repository = xmalloc (strlen (current_parsed_root->directory)
637                           + strlen (argv[0])
638                           + (mfile == NULL ? 0 : strlen (mfile))
639                           + 10);
640     (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
641     Sanitize_Repository_Name (repository);
642
643
644     /* save the original value of preload_update_dir */
645     if (preload_update_dir != NULL)
646         oldupdate = xstrdup (preload_update_dir);
647
648
649     /* Allocate space and set up the where variable.  We allocate more
650        space than necessary here so that we don't have to keep
651        reallocaing it later on. */
652     
653     where = xmalloc (strlen (argv[0])
654                      + (mfile == NULL ? 0 : strlen (mfile))
655                      + (mwhere == NULL ? 0 : strlen (mwhere))
656                      + (where_orig == NULL ? 0 : strlen (where_orig))
657                      + 10);
658
659     /* Yes, this could be written in a less verbose way, but in this
660        form it is quite easy to read.
661     
662        FIXME?  The following code that sets should probably be moved
663        to do_module in modules.c, since there is similar code in
664        patch.c and rtag.c. */
665     
666     if (shorten)
667     {
668         if (where_orig != NULL)
669         {
670             /* If the user has specified a directory with `-d' on the
671                command line, use it preferentially, even over the `-d'
672                flag in the modules file. */
673     
674             (void) strcpy (where, where_orig);
675         }
676         else if (mwhere != NULL)
677         {
678             /* Second preference is the value of mwhere, which is from
679                the `-d' flag in the modules file. */
680
681             (void) strcpy (where, mwhere);
682         }
683         else
684         {
685             /* Third preference is the directory specified in argv[0]
686                which is this module'e directory in the repository. */
687             
688             (void) strcpy (where, argv[0]);
689         }
690     }
691     else
692     {
693         /* Use the same preferences here, bug don't shorten -- that
694            is, tack on where_orig if it exists. */
695
696         *where = '\0';
697
698         if (where_orig != NULL)
699         {
700             (void) strcat (where, where_orig);
701             (void) strcat (where, "/");
702         }
703
704         /* If the -d flag in the modules file specified an absolute
705            directory, let the user override it with the command-line
706            -d option. */
707
708         if ((mwhere != NULL) && (! isabsolute (mwhere)))
709             (void) strcat (where, mwhere);
710         else
711             (void) strcat (where, argv[0]);
712     }
713     strip_trailing_slashes (where); /* necessary? */
714
715
716     /* At this point, the user may have asked for a single file or
717        directory from within a module.  In that case, we should modify
718        where, repository, and argv as appropriate. */
719
720     if (mfile != NULL)
721     {
722         /* The mfile variable can have one or more path elements.  If
723            it has multiple elements, we want to tack those onto both
724            repository and where.  The last element may refer to either
725            a file or directory.  Here's what to do:
726
727            it refers to a directory
728              -> simply tack it on to where and repository
729            it refers to a file
730              -> munge argv to contain `basename mfile` */
731
732         char *cp;
733         char *path;
734
735
736         /* Paranoia check. */
737
738         if (mfile[strlen (mfile) - 1] == '/')
739         {
740             error (0, 0, "checkout_proc: trailing slash on mfile (%s)!",
741                    mfile);
742         }
743
744
745         /* Does mfile have multiple path elements? */
746
747         cp = strrchr (mfile, '/');
748         if (cp != NULL)
749         {
750             *cp = '\0';
751             (void) strcat (repository, "/");
752             (void) strcat (repository, mfile);
753             (void) strcat (where, "/");
754             (void) strcat (where, mfile);
755             mfile = cp + 1;
756         }
757         
758
759         /* Now mfile is a single path element. */
760
761         path = xmalloc (strlen (repository) + strlen (mfile) + 5);
762         (void) sprintf (path, "%s/%s", repository, mfile);
763         if (isdir (path))
764         {
765             /* It's a directory, so tack it on to repository and
766                where, as we did above. */
767
768             (void) strcat (repository, "/");
769             (void) strcat (repository, mfile);
770             (void) strcat (where, "/");
771             (void) strcat (where, mfile);
772         }
773         else
774         {
775             /* It's a file, which means we have to screw around with
776                argv. */
777             myargv[0] = argv[0];
778             myargv[1] = mfile;
779             argc = 2;
780             argv = myargv;
781         }
782         free (path);
783     }
784
785     if (preload_update_dir != NULL)
786     {
787         preload_update_dir =
788             xrealloc (preload_update_dir,
789                       strlen (preload_update_dir) + strlen (where) + 5);
790         strcat (preload_update_dir, "/");
791         strcat (preload_update_dir, where);
792     }
793     else
794         preload_update_dir = xstrdup (where);
795
796     /*
797      * At this point, where is the directory we want to build, repository is
798      * the repository for the lowest level of the path.
799      *
800      * We need to tell build_dirs not only the path we want it to
801      * build, but also the repositories we want it to populate the
802      * path with.  To accomplish this, we walk the path backwards, one
803      * pathname component at a time, constucting a linked list of
804      * struct dir_to_build.
805      */
806
807     /*
808      * If we are sending everything to stdout, we can skip a whole bunch of
809      * work from here
810      */
811     if (!pipeout)
812     {
813         struct dir_to_build *head;
814         char *reposcopy;
815
816         if (strncmp (repository, current_parsed_root->directory,
817                      strlen (current_parsed_root->directory)) != 0)
818             error (1, 0, "\
819 internal error: %s doesn't start with %s in checkout_proc",
820                    repository, current_parsed_root->directory);
821
822         /* We always create at least one directory, which corresponds to
823            the entire strings for WHERE and REPOSITORY.  */
824         head = (struct dir_to_build *) xmalloc (sizeof (struct dir_to_build));
825         /* Special marker to indicate that we don't want build_dirs_and_chdir
826            to create the CVSADM directory for us.  */
827         head->repository = NULL;
828         head->dirpath = xstrdup (where);
829         head->next = NULL;
830         head->just_chdir = 0;
831
832
833         /* Make a copy of the repository name to play with. */
834         reposcopy = xstrdup (repository);
835
836         /* FIXME: this should be written in terms of last_component
837            instead of hardcoding '/'.  This presumably affects OS/2,
838            NT, &c, if the user specifies '\'.  Likewise for the call
839            to findslash.  */
840         cp = where + strlen (where);
841         while (cp > where)
842         {
843             struct dir_to_build *new;
844
845             cp = findslash (where, cp - 1);
846             if (cp == NULL)
847                 break;          /* we're done */
848
849             new = (struct dir_to_build *)
850                 xmalloc (sizeof (struct dir_to_build));
851             new->dirpath = xmalloc (strlen (where));
852
853             /* If the user specified an absolute path for where, the
854                last path element we create should be the top-level
855                directory. */
856
857             if (cp > where)
858             {
859                 strncpy (new->dirpath, where, cp - where);
860                 new->dirpath[cp - where] = '\0';
861             }
862             else
863             {
864                 /* where should always be at least one character long. */
865                 assert (where[0] != '\0');
866                 strcpy (new->dirpath, "/");
867             }
868             new->next = head;
869             head = new;
870
871             /* If where consists of multiple pathname components,
872                then we want to just cd into it, without creating
873                directories or modifying CVS directories as we go.
874                In CVS 1.9 and earlier, the code actually does a
875                CVS_CHDIR up-front; I'm not going to try to go back
876                to that exact code but this is somewhat similar
877                in spirit.  */
878             if (where_orig != NULL
879                 && cp - where < strlen (where_orig))
880             {
881                 new->repository = NULL;
882                 new->just_chdir = 1;
883                 continue;
884             }
885
886             new->just_chdir = 0;
887
888             /* Now figure out what repository directory to generate.
889                The most complete case would be something like this:
890
891                The modules file contains
892                  foo -d bar/baz quux
893
894                The command issued was:
895                  cvs co -d what/ever -N foo
896                
897                The results in the CVS/Repository files should be:
898                  .     -> (don't touch CVS/Repository)
899                           (I think this case might be buggy currently)
900                  what  -> (don't touch CVS/Repository)
901                  ever  -> .          (same as "cd what/ever; cvs co -N foo")
902                  bar   -> Emptydir   (generated dir -- not in repos)
903                  baz   -> quux       (finally!) */
904
905             if (strcmp (reposcopy, current_parsed_root->directory) == 0)
906             {
907                 /* We can't walk up past CVSROOT.  Instead, the
908                    repository should be Emptydir. */
909                 new->repository = emptydir_name ();
910             }
911             else
912             {
913                 /* It's a directory in the repository! */
914                     
915                 char *rp;
916                     
917                 /* We'll always be below CVSROOT, but check for
918                    paranoia's sake. */
919                 rp = strrchr (reposcopy, '/');
920                 if (rp == NULL)
921                     error (1, 0,
922                            "internal error: %s doesn't contain a slash",
923                            reposcopy);
924                            
925                 *rp = '\0';
926                 new->repository = xmalloc (strlen (reposcopy) + 5);
927                 (void) strcpy (new->repository, reposcopy);
928                     
929                 if (strcmp (reposcopy, current_parsed_root->directory) == 0)
930                 {
931                     /* Special case -- the repository name needs
932                        to be "/path/to/repos/." (the trailing dot
933                        is important).  We might be able to get rid
934                        of this after the we check out the other
935                        code that handles repository names. */
936                     (void) strcat (new->repository, "/.");
937                 }
938             }
939         }
940
941         /* clean up */
942         free (reposcopy);
943
944         /* The top-level CVSADM directory should always be
945            current_parsed_root->directory.  Create it, but only if WHERE is
946            relative.  If WHERE is absolute, our current directory
947            may not have a thing to do with where the sources are
948            being checked out.  If it does, build_dirs_and_chdir
949            will take care of creating adm files here. */
950         /* FIXME: checking is_absolute (where) is a horrid kludge;
951            I suspect we probably can just skip the call to
952            build_one_dir whenever the -d command option was specified
953            to checkout.  */
954
955         if (!isabsolute (where) && top_level_admin && m_type == CHECKOUT)
956         {
957             /* It may be argued that we shouldn't set any sticky
958                bits for the top-level repository.  FIXME?  */
959             build_one_dir (current_parsed_root->directory, ".", argc <= 1);
960
961 #ifdef SERVER_SUPPORT
962             /* We _always_ want to have a top-level admin
963                directory.  If we're running in client/server mode,
964                send a "Clear-static-directory" command to make
965                sure it is created on the client side.  (See 5.10
966                in cvsclient.dvi to convince yourself that this is
967                OK.)  If this is a duplicate command being sent, it
968                will be ignored on the client side.  */
969
970             if (server_active)
971                 server_clear_entstat (".", current_parsed_root->directory);
972 #endif
973         }
974
975
976         /* Build dirs on the path if necessary and leave us in the
977            bottom directory (where if where was specified) doesn't
978            contain a CVS subdir yet, but all the others contain
979            CVS and Entries.Static files */
980
981         if (build_dirs_and_chdir (head, argc <= 1) != 0)
982         {
983             error (0, 0, "ignoring module %s", omodule);
984             err = 1;
985             goto out;
986         }
987
988         /* set up the repository (or make sure the old one matches) */
989         if (!isfile (CVSADM))
990         {
991             FILE *fp;
992
993             if (!noexec && argc > 1)
994             {
995                 /* I'm not sure whether this check is redundant.  */
996                 if (!isdir (repository))
997                     error (1, 0, "there is no repository %s", repository);
998
999                 Create_Admin (".", preload_update_dir, repository,
1000                               (char *) NULL, (char *) NULL, 0, 0,
1001                               m_type == CHECKOUT);
1002                 fp = open_file (CVSADM_ENTSTAT, "w+");
1003                 if (fclose(fp) == EOF)
1004                     error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
1005 #ifdef SERVER_SUPPORT
1006                 if (server_active)
1007                     server_set_entstat (where, repository);
1008 #endif
1009             }
1010             else
1011             {
1012                 /* I'm not sure whether this check is redundant.  */
1013                 if (!isdir (repository))
1014                     error (1, 0, "there is no repository %s", repository);
1015
1016                 Create_Admin (".", preload_update_dir, repository, tag, date,
1017
1018                               /* FIXME?  This is a guess.  If it is important
1019                                  for nonbranch to be set correctly here I
1020                                  think we need to write it one way now and
1021                                  then rewrite it later via WriteTag, once
1022                                  we've had a chance to call RCS_nodeisbranch
1023                                  on each file.  */
1024                               0, 0, m_type == CHECKOUT);
1025             }
1026         }
1027         else
1028         {
1029             char *repos;
1030
1031             if (m_type == EXPORT)
1032                 error (1, 0, "cannot export into working directory");
1033
1034             /* get the contents of the previously existing repository */
1035             repos = Name_Repository ((char *) NULL, preload_update_dir);
1036             if (fncmp (repository, repos) != 0)
1037             {
1038                 error (0, 0, "existing repository %s does not match %s",
1039                        repos, repository);
1040                 error (0, 0, "ignoring module %s", omodule);
1041                 free (repos);
1042                 err = 1;
1043                 goto out;
1044             }
1045             free (repos);
1046         }
1047     }
1048
1049     /*
1050      * If we are going to be updating to stdout, we need to cd to the
1051      * repository directory so the recursion processor can use the current
1052      * directory as the place to find repository information
1053      */
1054     if (pipeout)
1055     {
1056         if ( CVS_CHDIR (repository) < 0)
1057         {
1058             error (0, errno, "cannot chdir to %s", repository);
1059             err = 1;
1060             goto out;
1061         }
1062         which = W_REPOS;
1063         if (tag != NULL && !tag_validated)
1064         {
1065             tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, NULL);
1066             tag_validated = 1;
1067         }
1068     }
1069     else
1070     {
1071         which = W_LOCAL | W_REPOS;
1072         if (tag != NULL && !tag_validated)
1073         {
1074             tag_check_valid (tag, argc - 1, argv + 1, 0, aflag,
1075                              repository);
1076             tag_validated = 1;
1077         }
1078     }
1079
1080     if (tag != NULL || date != NULL || join_rev1 != NULL)
1081         which |= W_ATTIC;
1082
1083     if (! join_tags_validated)
1084     {
1085         if (join_rev1 != NULL)
1086             tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag,
1087                                   repository);
1088         if (join_rev2 != NULL)
1089             tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag,
1090                                   repository);
1091         join_tags_validated = 1;
1092     }
1093
1094     /*
1095      * if we are going to be recursive (building dirs), go ahead and call the
1096      * update recursion processor.  We will be recursive unless either local
1097      * only was specified, or we were passed arguments
1098      */
1099     if (!(local_specified || argc > 1))
1100     {
1101         if (!pipeout)
1102             history_write (m_type == CHECKOUT ? 'O' : 'E', preload_update_dir,
1103                            history_name, where, repository);
1104         err += do_update (0, (char **) NULL, options, tag, date,
1105                           force_tag_match, 0 /* !local */ ,
1106                           1 /* update -d */ , aflag, checkout_prune_dirs,
1107                           pipeout, which, join_rev1, join_rev2,
1108                           preload_update_dir, pull_template, repository);
1109         goto out;
1110     }
1111
1112     if (!pipeout)
1113     {
1114         int i;
1115         List *entries;
1116
1117         /* we are only doing files, so register them */
1118         entries = Entries_Open (0, NULL);
1119         for (i = 1; i < argc; i++)
1120         {
1121             char *line;
1122             Vers_TS *vers;
1123             struct file_info finfo;
1124
1125             memset (&finfo, 0, sizeof finfo);
1126             finfo.file = argv[i];
1127             /* Shouldn't be used, so set to arbitrary value.  */
1128             finfo.update_dir = NULL;
1129             finfo.fullname = argv[i];
1130             finfo.repository = repository;
1131             finfo.entries = entries;
1132             /* The rcs slot is needed to get the options from the RCS
1133                file */
1134             finfo.rcs = RCS_parse (finfo.file, repository);
1135
1136             vers = Version_TS (&finfo, options, tag, date,
1137                                force_tag_match, 0);
1138             if (vers->ts_user == NULL)
1139             {
1140                 line = xmalloc (strlen (finfo.file) + 15);
1141                 (void) sprintf (line, "Initial %s", finfo.file);
1142                 Register (entries, finfo.file,
1143                           vers->vn_rcs ? vers->vn_rcs : "0",
1144                           line, vers->options, vers->tag,
1145                           vers->date, (char *) 0);
1146                 free (line);
1147             }
1148             freevers_ts (&vers);
1149             freercsnode (&finfo.rcs);
1150         }
1151
1152         Entries_Close (entries);
1153     }
1154
1155     /* Don't log "export", just regular "checkouts" */
1156     if (m_type == CHECKOUT && !pipeout)
1157         history_write ('O', preload_update_dir, history_name, where,
1158                        repository);
1159
1160     /* go ahead and call update now that everything is set */
1161     err += do_update (argc - 1, argv + 1, options, tag, date,
1162                       force_tag_match, local_specified, 1 /* update -d */,
1163                       aflag, checkout_prune_dirs, pipeout, which, join_rev1,
1164                       join_rev2, preload_update_dir, pull_template, repository);
1165 out:
1166     free (preload_update_dir);
1167     preload_update_dir = oldupdate;
1168     free (where);
1169     free (repository);
1170     return (err);
1171 }
1172
1173 static char *
1174 findslash (start, p)
1175     char *start;
1176     char *p;
1177 {
1178     for (;;)
1179     {
1180         if (*p == '/') return p;
1181         if (p == start) break;
1182         --p;
1183     }
1184     return NULL;
1185 }
1186
1187 /* Return a newly malloc'd string containing a pathname for CVSNULLREPOS,
1188    and make sure that it exists.  If there is an error creating the
1189    directory, give a fatal error.  Otherwise, the directory is guaranteed
1190    to exist when we return.  */
1191 char *
1192 emptydir_name ()
1193 {
1194     char *repository;
1195
1196     repository = xmalloc (strlen (current_parsed_root->directory) 
1197                           + sizeof (CVSROOTADM)
1198                           + sizeof (CVSNULLREPOS)
1199                           + 3);
1200     (void) sprintf (repository, "%s/%s/%s", current_parsed_root->directory,
1201                     CVSROOTADM, CVSNULLREPOS);
1202     if (!isfile (repository))
1203     {
1204         mode_t omask;
1205         omask = umask (cvsumask);
1206         if (CVS_MKDIR (repository, 0777) < 0)
1207             error (1, errno, "cannot create %s", repository);
1208         (void) umask (omask);
1209     }
1210     return repository;
1211 }
1212
1213 /* Build all the dirs along the path to DIRS with CVS subdirs with appropriate
1214  * repositories.  If DIRS->repository is NULL or the directory already exists,
1215  * do not create a CVSADM directory for that subdirectory; just CVS_CHDIR into
1216  * it.  Frees all storage used by DIRS.
1217  *
1218  * ASSUMPTIONS
1219  *   1. Parent directories will be listed in DIRS before their children.
1220  *   2. At most a single directory will need to be changed at one time.  In
1221  *      other words, if we are in /a/b/c, and our final destination is
1222  *      /a/b/c/d/e/f, then we will build d, then d/e, then d/e/f.
1223  *
1224  * INPUTS
1225  *   dirs       Simple list composed of dir_to_build structures, listing
1226  *              information about directories to build.
1227  *   sticky     Passed to build_one_dir to tell it whether there are any sticky
1228  *              tags or dates to be concerned with.
1229  *
1230  * RETURNS
1231  *   1 on error, 0 otherwise.
1232  *
1233  * ERRORS
1234  *  The only nonfatal error this function may return is if the CHDIR fails.
1235  */
1236 static int
1237 build_dirs_and_chdir (dirs, sticky)
1238     struct dir_to_build *dirs;
1239     int sticky;
1240 {
1241     int retval = 0;
1242     struct dir_to_build *nextdir;
1243
1244     while (dirs != NULL)
1245     {
1246         const char *dir = last_component (dirs->dirpath);
1247
1248         if (!dirs->just_chdir)
1249         {
1250             mkdir_if_needed (dir);
1251             Subdir_Register (NULL, NULL, dir);
1252         }
1253
1254         if (CVS_CHDIR (dir) < 0)
1255         {
1256             error (0, errno, "cannot chdir to %s", dir);
1257             retval = 1;
1258             goto out;
1259         }
1260         if (dirs->repository != NULL)
1261         {
1262             build_one_dir (dirs->repository, dirs->dirpath, sticky);
1263             free (dirs->repository);
1264         }
1265         nextdir = dirs->next;
1266         free (dirs->dirpath);
1267         free (dirs);
1268         dirs = nextdir;
1269     }
1270
1271  out:
1272     while (dirs != NULL)
1273     {
1274         if (dirs->repository != NULL)
1275             free (dirs->repository);
1276         nextdir = dirs->next;
1277         free (dirs->dirpath);
1278         free (dirs);
1279         dirs = nextdir;
1280     }
1281     return retval;
1282 }