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