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