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: stable/9/contrib/cvs/src/checkout.c 175265 2008-01-13 06:00:42Z obrien $
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
checkout(argc,argv)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
safe_location(where)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
build_one_dir(repository,dirpath,sticky)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
checkout_proc(argc,argv,where_orig,mwhere,mfile,shorten,local_specified,omodule,msg)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 *
findslash(start,p)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 *
emptydir_name()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
build_dirs_and_chdir(dirs,sticky)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 }
1285