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