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