Commit | Line | Data |
---|---|---|
210114b7 WJ |
1 | /* |
2 | * Copyright (c) 1992, Brian Berliner and Jeff Polk | |
3 | * Copyright (c) 1989-1992, Brian Berliner | |
4 | * | |
5 | * You may distribute under the terms of the GNU General Public License as | |
6 | * specified in the README file that comes with the CVS 1.3 kit. | |
7 | * | |
8 | * Create Version | |
9 | * | |
10 | * "checkout" creates a "version" of an RCS repository. This version is owned | |
11 | * totally by the user and is actually an independent copy, to be dealt with | |
12 | * as seen fit. Once "checkout" has been called in a given directory, it | |
13 | * never needs to be called again. The user can keep up-to-date by calling | |
14 | * "update" when he feels like it; this will supply him with a merge of his | |
15 | * own modifications and the changes made in the RCS original. See "update" | |
16 | * for details. | |
17 | * | |
18 | * "checkout" can be given a list of directories or files to be updated and in | |
19 | * the case of a directory, will recursivley create any sub-directories that | |
20 | * exist in the repository. | |
21 | * | |
22 | * When the user is satisfied with his own modifications, the present version | |
23 | * can be committed by "commit"; this keeps the present version in tact, | |
24 | * usually. | |
25 | * | |
26 | * The call is cvs checkout [options] <module-name>... | |
27 | * | |
28 | * "checkout" creates a directory ./CVS, in which it keeps its administration, | |
29 | * in two files, Repository and Entries. The first contains the name of the | |
30 | * repository. The second contains one line for each registered file, | |
31 | * consisting of the version number it derives from, its time stamp at | |
32 | * derivation time and its name. Both files are normal files and can be | |
33 | * edited by the user, if necessary (when the repository is moved, e.g.) | |
34 | */ | |
35 | ||
36 | #include "cvs.h" | |
37 | ||
38 | #ifndef lint | |
39 | static char rcsid[] = "@(#)checkout.c 1.67 92/04/10"; | |
40 | #endif | |
41 | ||
42 | #if __STDC__ | |
43 | static char *findslash (char *start, char *p); | |
44 | static int build_dirs_and_chdir (char *dir, char *prepath, char *realdir, | |
45 | int sticky); | |
46 | static int checkout_proc (int *pargc, char *argv[], char *where, | |
47 | char *mwhere, char *mfile, int shorten, | |
48 | int local_specified, char *omodule, | |
49 | char *msg); | |
50 | #else | |
51 | static int checkout_proc (); | |
52 | static char *findslash (); | |
53 | static int build_dirs_and_chdir (); | |
54 | #endif /* __STDC__ */ | |
55 | ||
56 | static char *checkout_usage[] = | |
57 | { | |
58 | "Usage:\n %s %s [-ANPQcflnpqs] [-r rev | -D date] [-d dir] [-k kopt] modules...\n", | |
59 | "\t-A\tReset any sticky tags/date/kopts.\n", | |
60 | "\t-N\tDon't shorten module paths if -d specified.\n", | |
61 | "\t-P\tPrune empty directories.\n", | |
62 | "\t-Q\tReally quiet.\n", | |
63 | "\t-c\t\"cat\" the module database.\n", | |
64 | "\t-f\tForce a head revision match if tag/date not found.\n", | |
65 | "\t-l\tLocal directory only, not recursive\n", | |
66 | "\t-n\tDo not run module program (if any).\n", | |
67 | "\t-p\tCheck out files to standard output.\n", | |
68 | "\t-q\tSomewhat quiet.\n", | |
69 | "\t-s\tLike -c, but include module status.\n", | |
70 | "\t-r rev\tCheck out revision or tag. (implies -P)\n", | |
71 | "\t-D date\tCheck out revisions as of date. (implies -P)\n", | |
72 | "\t-d dir\tCheck out into dir instead of module name.\n", | |
73 | "\t-k kopt\tUse RCS kopt -k option on checkout.\n", | |
74 | "\t-j rev\tMerge in changes made between current revision and rev.\n", | |
75 | NULL | |
76 | }; | |
77 | ||
78 | static char *export_usage[] = | |
79 | { | |
80 | "Usage: %s %s [-NPQflnq] [-r rev | -D date] [-d dir] module...\n", | |
81 | "\t-N\tDon't shorten module paths if -d specified.\n", | |
82 | "\t-Q\tReally quiet.\n", | |
83 | "\t-f\tForce a head revision match if tag/date not found.\n", | |
84 | "\t-l\tLocal directory only, not recursive\n", | |
85 | "\t-n\tDo not run module program (if any).\n", | |
86 | "\t-q\tSomewhat quiet.\n", | |
87 | "\t-r rev\tCheck out revision or tag. (implies -P)\n", | |
88 | "\t-D date\tCheck out revisions as of date. (implies -P)\n", | |
89 | "\t-d dir\tCheck out into dir instead of module name.\n", | |
90 | NULL | |
91 | }; | |
92 | ||
93 | static int checkout_prune_dirs; | |
94 | static int force_tag_match = 1; | |
95 | static int pipeout; | |
96 | static int aflag; | |
97 | static char *options = NULL; | |
98 | static char *tag = NULL; | |
99 | static char *date = NULL; | |
100 | static char *join_rev1 = NULL; | |
101 | static char *join_rev2 = NULL; | |
102 | static char *preload_update_dir = NULL; | |
103 | ||
104 | int | |
105 | checkout (argc, argv) | |
106 | int argc; | |
107 | char *argv[]; | |
108 | { | |
109 | register int i; | |
110 | int c; | |
111 | DBM *db; | |
112 | int cat = 0, err = 0, status = 0; | |
113 | int run_module_prog = 1; | |
114 | int local = 0; | |
115 | int shorten = -1; | |
116 | char *where = NULL; | |
117 | char *valid_options, **valid_usage; | |
118 | ||
119 | /* | |
120 | * A smaller subset of options are allowed for the export command, which | |
121 | * is essentially like checkout, except that it hard-codes certain | |
122 | * options to be on (like -kv) and takes care to remove the CVS directory | |
123 | * when it has done its duty | |
124 | */ | |
125 | if (strcmp (command_name, "export") == 0) | |
126 | { | |
127 | valid_options = "Nnd:flRQqr:D:"; | |
128 | valid_usage = export_usage; | |
129 | } | |
130 | else | |
131 | { | |
132 | valid_options = "ANnk:d:flRpQqcsr:D:j:P"; | |
133 | valid_usage = checkout_usage; | |
134 | } | |
135 | ||
136 | if (argc == -1) | |
137 | usage (valid_usage); | |
138 | ||
139 | ign_setup (); | |
140 | ||
141 | optind = 1; | |
142 | while ((c = gnu_getopt (argc, argv, valid_options)) != -1) | |
143 | { | |
144 | switch (c) | |
145 | { | |
146 | case 'A': | |
147 | aflag = 1; | |
148 | break; | |
149 | case 'N': | |
150 | shorten = 0; | |
151 | break; | |
152 | case 'k': | |
153 | if (options) | |
154 | free (options); | |
155 | options = RCS_check_kflag (optarg); | |
156 | break; | |
157 | case 'n': | |
158 | run_module_prog = 0; | |
159 | break; | |
160 | case 'Q': | |
161 | really_quiet = 1; | |
162 | /* FALL THROUGH */ | |
163 | case 'q': | |
164 | quiet = 1; | |
165 | break; | |
166 | case 'l': | |
167 | local = 1; | |
168 | break; | |
169 | case 'R': | |
170 | local = 0; | |
171 | break; | |
172 | case 'P': | |
173 | checkout_prune_dirs = 1; | |
174 | break; | |
175 | case 'p': | |
176 | pipeout = 1; | |
177 | run_module_prog = 0; /* don't run module prog when piping */ | |
178 | noexec = 1; /* so no locks will be created */ | |
179 | break; | |
180 | case 'c': | |
181 | cat = 1; | |
182 | break; | |
183 | case 'd': | |
184 | where = optarg; | |
185 | if (shorten == -1) | |
186 | shorten = 1; | |
187 | break; | |
188 | case 's': | |
189 | status = 1; | |
190 | break; | |
191 | case 'f': | |
192 | force_tag_match = 0; | |
193 | break; | |
194 | case 'r': | |
195 | tag = optarg; | |
196 | checkout_prune_dirs = 1; | |
197 | break; | |
198 | case 'D': | |
199 | date = Make_Date (optarg); | |
200 | checkout_prune_dirs = 1; | |
201 | break; | |
202 | case 'j': | |
203 | if (join_rev2) | |
204 | error (1, 0, "only two -j options can be specified"); | |
205 | if (join_rev1) | |
206 | join_rev2 = optarg; | |
207 | else | |
208 | join_rev1 = optarg; | |
209 | break; | |
210 | case '?': | |
211 | default: | |
212 | usage (valid_usage); | |
213 | break; | |
214 | } | |
215 | } | |
216 | argc -= optind; | |
217 | argv += optind; | |
218 | ||
219 | if (shorten == -1) | |
220 | shorten = 0; | |
221 | ||
222 | if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0) | |
223 | || (tag && date)) | |
224 | usage (valid_usage); | |
225 | ||
226 | if (where && pipeout) | |
227 | error (1, 0, "-d and -p are mutually exclusive"); | |
228 | ||
229 | if (strcmp (command_name, "export") == 0) | |
230 | { | |
231 | if (!tag && !date) | |
232 | { | |
233 | error (0, 0, "must specify a tag or date"); | |
234 | usage (valid_usage); | |
235 | } | |
236 | if (tag && isdigit (tag[0])) | |
237 | error (1, 0, "tag `%s' must be a symbolic tag", tag); | |
238 | options = RCS_check_kflag ("v");/* -kv must be on */ | |
239 | } | |
240 | ||
241 | if (cat || status) | |
242 | { | |
243 | cat_module (status); | |
244 | return (0); | |
245 | } | |
246 | db = open_module (); | |
247 | ||
248 | /* | |
249 | * if we have more than one argument and where was specified, we make the | |
250 | * where, cd into it, and try to shorten names as much as possible. | |
251 | * Otherwise, we pass the where as a single argument to do_module. | |
252 | */ | |
253 | if (argc > 1 && where != NULL) | |
254 | { | |
255 | char repository[PATH_MAX]; | |
256 | ||
257 | (void) mkdir (where, 0777); | |
258 | if (chdir (where) < 0) | |
259 | error (1, errno, "cannot chdir to %s", where); | |
260 | preload_update_dir = xstrdup (where); | |
261 | where = (char *) NULL; | |
262 | if (!isfile (CVSADM) && !isfile (OCVSADM)) | |
263 | { | |
264 | (void) sprintf (repository, "%s/%s", CVSroot, CVSNULLREPOS); | |
265 | if (!isfile (repository)) | |
266 | (void) mkdir (repository, 0777); | |
267 | Create_Admin (".", repository, (char *) NULL, (char *) NULL); | |
268 | if (!noexec) | |
269 | { | |
270 | FILE *fp; | |
271 | ||
272 | fp = open_file (CVSADM_ENTSTAT, "w+"); | |
273 | if (fclose(fp) == EOF) | |
274 | error(1, errno, "cannot close %s", CVSADM_ENTSTAT); | |
275 | } | |
276 | } | |
277 | } | |
278 | ||
279 | /* | |
280 | * if where was specified (-d) and we have not taken care of it already | |
281 | * with the multiple arg stuff, and it was not a simple directory name | |
282 | * but rather a path, we strip off everything but the last component and | |
283 | * attempt to cd to the indicated place. where then becomes simply the | |
284 | * last component | |
285 | */ | |
286 | if (where != NULL && index (where, '/') != NULL) | |
287 | { | |
288 | char *slash; | |
289 | ||
290 | slash = rindex (where, '/'); | |
291 | *slash = '\0'; | |
292 | ||
293 | if (chdir (where) < 0) | |
294 | error (1, errno, "cannot chdir to %s", where); | |
295 | ||
296 | preload_update_dir = xstrdup (where); | |
297 | ||
298 | where = slash + 1; | |
299 | if (*where == '\0') | |
300 | where = NULL; | |
301 | } | |
302 | ||
303 | for (i = 0; i < argc; i++) | |
304 | err += do_module (db, argv[i], CHECKOUT, "Updating", checkout_proc, | |
305 | where, shorten, local, run_module_prog, | |
306 | (char *) NULL); | |
307 | close_module (db); | |
308 | return (err); | |
309 | } | |
310 | ||
311 | /* | |
312 | * process_module calls us back here so we do the actual checkout stuff | |
313 | */ | |
314 | /* ARGSUSED */ | |
315 | static int | |
316 | checkout_proc (pargc, argv, where, mwhere, mfile, shorten, | |
317 | local_specified, omodule, msg) | |
318 | int *pargc; | |
319 | char *argv[]; | |
320 | char *where; | |
321 | char *mwhere; | |
322 | char *mfile; | |
323 | int shorten; | |
324 | int local_specified; | |
325 | char *omodule; | |
326 | char *msg; | |
327 | { | |
328 | int err = 0; | |
329 | int which; | |
330 | char *cp; | |
331 | char *cp2; | |
332 | char repository[PATH_MAX]; | |
333 | char xwhere[PATH_MAX]; | |
334 | char *oldupdate = NULL; | |
335 | char *prepath; | |
336 | char *realdirs; | |
337 | ||
338 | /* | |
339 | * OK, so we're doing the checkout! Our args are as follows: | |
340 | * argc,argv contain either dir or dir followed by a list of files | |
341 | * where contains where to put it (if supplied by checkout) | |
342 | * mwhere contains the module name or -d from module file | |
343 | * mfile says do only that part of the module | |
344 | * shorten = TRUE says shorten as much as possible | |
345 | * omodule is the original arg to do_module() | |
346 | */ | |
347 | ||
348 | /* set up the repository (maybe) for the bottom directory */ | |
349 | (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); | |
350 | ||
351 | /* save the original value of preload_update_dir */ | |
352 | if (preload_update_dir != NULL) | |
353 | oldupdate = xstrdup (preload_update_dir); | |
354 | ||
355 | /* fix up argv[] for the case of partial modules */ | |
356 | if (mfile != NULL) | |
357 | { | |
358 | char file[PATH_MAX]; | |
359 | ||
360 | /* if mfile is really a path, straighten it out first */ | |
361 | if ((cp = rindex (mfile, '/')) != NULL) | |
362 | { | |
363 | *cp = 0; | |
364 | (void) strcat (repository, "/"); | |
365 | (void) strcat (repository, mfile); | |
366 | ||
367 | /* | |
368 | * Now we need to fill in the where correctly. if !shorten, tack | |
369 | * the rest of the path onto where if where is filled in | |
370 | * otherwise tack the rest of the path onto mwhere and make that | |
371 | * the where | |
372 | * | |
373 | * If shorten is enabled, we might use mwhere to set where if | |
374 | * nobody set it yet, so we'll need to setup mwhere as the last | |
375 | * component of the path we are tacking onto repository | |
376 | */ | |
377 | if (!shorten) | |
378 | { | |
379 | if (where != NULL) | |
380 | (void) sprintf (xwhere, "%s/%s", where, mfile); | |
381 | else | |
382 | (void) sprintf (xwhere, "%s/%s", mwhere, mfile); | |
383 | where = xwhere; | |
384 | } | |
385 | else | |
386 | { | |
387 | char *slash; | |
388 | ||
389 | if ((slash = rindex (mfile, '/')) != NULL) | |
390 | mwhere = slash + 1; | |
391 | else | |
392 | mwhere = mfile; | |
393 | } | |
394 | mfile = cp + 1; | |
395 | } | |
396 | ||
397 | (void) sprintf (file, "%s/%s", repository, mfile); | |
398 | if (isdir (file)) | |
399 | { | |
400 | ||
401 | /* | |
402 | * The portion of a module was a directory, so kludge up where to | |
403 | * be the subdir, and fix up repository | |
404 | */ | |
405 | (void) strcpy (repository, file); | |
406 | ||
407 | /* | |
408 | * At this point, if shorten is not enabled, we make where either | |
409 | * where with mfile concatenated, or if where hadn't been set we | |
410 | * set it to mwhere with mfile concatenated. | |
411 | * | |
412 | * If shorten is enabled and where hasn't been set yet, then where | |
413 | * becomes mfile | |
414 | */ | |
415 | if (!shorten) | |
416 | { | |
417 | if (where != NULL) | |
418 | (void) sprintf (xwhere, "%s/%s", where, mfile); | |
419 | else | |
420 | (void) sprintf (xwhere, "%s/%s", mwhere, mfile); | |
421 | where = xwhere; | |
422 | } | |
423 | else if (where == NULL) | |
424 | where = mfile; | |
425 | } | |
426 | else | |
427 | { | |
428 | int i; | |
429 | ||
430 | /* | |
431 | * The portion of a module was a file, so kludge up argv to be | |
432 | * correct | |
433 | */ | |
434 | for (i = 1; i < *pargc; i++)/* free the old ones */ | |
435 | free (argv[i]); | |
436 | argv[1] = xstrdup (mfile); /* set up the new one */ | |
437 | *pargc = 2; | |
438 | ||
439 | /* where gets mwhere if where isn't set */ | |
440 | if (where == NULL) | |
441 | where = mwhere; | |
442 | } | |
443 | } | |
444 | ||
445 | /* | |
446 | * if shorten is enabled and where isn't specified yet, we pluck the last | |
447 | * directory component of argv[0] and make it the where | |
448 | */ | |
449 | if (shorten && where == NULL) | |
450 | { | |
451 | if ((cp = rindex (argv[0], '/')) != NULL) | |
452 | { | |
453 | (void) strcpy (xwhere, cp + 1); | |
454 | where = xwhere; | |
455 | } | |
456 | } | |
457 | ||
458 | /* if where is still NULL, use mwhere if set or the argv[0] dir */ | |
459 | if (where == NULL) | |
460 | { | |
461 | if (mwhere) | |
462 | where = mwhere; | |
463 | else | |
464 | { | |
465 | (void) strcpy (xwhere, argv[0]); | |
466 | where = xwhere; | |
467 | } | |
468 | } | |
469 | ||
470 | if (preload_update_dir != NULL) | |
471 | { | |
472 | char tmp[PATH_MAX]; | |
473 | ||
474 | (void) sprintf (tmp, "%s/%s", preload_update_dir, where); | |
475 | free (preload_update_dir); | |
476 | preload_update_dir = xstrdup (tmp); | |
477 | } | |
478 | else | |
479 | preload_update_dir = xstrdup (where); | |
480 | ||
481 | /* | |
482 | * At this point, where is the directory we want to build, repository is | |
483 | * the repository for the lowest level of the path. | |
484 | */ | |
485 | ||
486 | /* | |
487 | * If we are sending everything to stdout, we can skip a whole bunch of | |
488 | * work from here | |
489 | */ | |
490 | if (!pipeout) | |
491 | { | |
492 | ||
493 | /* | |
494 | * We need to tell build_dirs not only the path we want it to build, | |
495 | * but also the repositories we want it to populate the path with. To | |
496 | * accomplish this, we pass build_dirs a ``real path'' with valid | |
497 | * repositories and a string to pre-pend based on how many path | |
498 | * elements exist in where. Big Black Magic | |
499 | */ | |
500 | prepath = xstrdup (repository); | |
501 | cp = rindex (where, '/'); | |
502 | cp2 = rindex (prepath, '/'); | |
503 | while (cp != NULL) | |
504 | { | |
505 | cp = findslash (where, cp - 1); | |
506 | cp2 = findslash (prepath, cp2 - 1); | |
507 | } | |
508 | *cp2 = '\0'; | |
509 | realdirs = cp2 + 1; | |
510 | ||
511 | /* | |
512 | * build dirs on the path if necessary and leave us in the bottom | |
513 | * directory (where if where was specified) doesn't contain a CVS | |
514 | * subdir yet, but all the others contain CVS and Entries.Static | |
515 | * files | |
516 | */ | |
517 | if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0) | |
518 | { | |
519 | error (0, 0, "ignoring module %s", omodule); | |
520 | free (prepath); | |
521 | free (preload_update_dir); | |
522 | preload_update_dir = oldupdate; | |
523 | return (1); | |
524 | } | |
525 | ||
526 | /* clean up */ | |
527 | free (prepath); | |
528 | ||
529 | /* set up the repository (or make sure the old one matches) */ | |
530 | if (!isfile (CVSADM) && !isfile (OCVSADM)) | |
531 | { | |
532 | FILE *fp; | |
533 | ||
534 | if (!noexec && *pargc > 1) | |
535 | { | |
536 | Create_Admin (".", repository, (char *) NULL, (char *) NULL); | |
537 | fp = open_file (CVSADM_ENTSTAT, "w+"); | |
538 | if (fclose(fp) == EOF) | |
539 | error(1, errno, "cannot close %s", CVSADM_ENTSTAT); | |
540 | } | |
541 | else | |
542 | Create_Admin (".", repository, tag, date); | |
543 | } | |
544 | else | |
545 | { | |
546 | char *repos; | |
547 | ||
548 | /* get the contents of the previously existing repository */ | |
549 | repos = Name_Repository ((char *) NULL, preload_update_dir); | |
550 | if (strcmp (repository, repos) != 0) | |
551 | { | |
552 | error (0, 0, "existing repository %s does not match %s", | |
553 | repos, repository); | |
554 | error (0, 0, "ignoring module %s", omodule); | |
555 | free (repos); | |
556 | free (preload_update_dir); | |
557 | preload_update_dir = oldupdate; | |
558 | return (1); | |
559 | } | |
560 | free (repos); | |
561 | } | |
562 | } | |
563 | ||
564 | /* | |
565 | * If we are going to be updating to stdout, we need to cd to the | |
566 | * repository directory so the recursion processor can use the current | |
567 | * directory as the place to find repository information | |
568 | */ | |
569 | if (pipeout) | |
570 | { | |
571 | if (chdir (repository) < 0) | |
572 | { | |
573 | error (0, errno, "cannot chdir to %s", repository); | |
574 | free (preload_update_dir); | |
575 | preload_update_dir = oldupdate; | |
576 | return (1); | |
577 | } | |
578 | which = W_REPOS; | |
579 | } | |
580 | else | |
581 | which = W_LOCAL | W_REPOS; | |
582 | ||
583 | if (tag != NULL || date != NULL) | |
584 | which |= W_ATTIC; | |
585 | ||
586 | /* | |
587 | * if we are going to be recursive (building dirs), go ahead and call the | |
588 | * update recursion processor. We will be recursive unless either local | |
589 | * only was specified, or we were passed arguments | |
590 | */ | |
591 | if (!(local_specified || *pargc > 1)) | |
592 | { | |
593 | if (strcmp (command_name, "export") != 0 && !pipeout) | |
594 | history_write ('O', preload_update_dir, tag ? tag : date, where, | |
595 | repository); | |
596 | err += do_update (0, (char **) NULL, options, tag, date, | |
597 | force_tag_match, 0 /* !local */ , | |
598 | 1 /* update -d */ , aflag, checkout_prune_dirs, | |
599 | pipeout, which, join_rev1, join_rev2, | |
600 | preload_update_dir); | |
601 | free (preload_update_dir); | |
602 | preload_update_dir = oldupdate; | |
603 | return (err); | |
604 | } | |
605 | ||
606 | if (!pipeout) | |
607 | { | |
608 | int i; | |
609 | List *entries; | |
610 | ||
611 | /* we are only doing files, so register them */ | |
612 | entries = ParseEntries (0); | |
613 | for (i = 1; i < *pargc; i++) | |
614 | { | |
615 | char line[MAXLINELEN]; | |
616 | char *user; | |
617 | Vers_TS *vers; | |
618 | ||
619 | user = argv[i]; | |
620 | vers = Version_TS (repository, options, tag, date, user, | |
621 | force_tag_match, 0, entries, (List *) NULL); | |
622 | if (vers->ts_user == NULL) | |
623 | { | |
624 | (void) sprintf (line, "Initial %s", user); | |
625 | Register (entries, user, vers->vn_rcs, line, vers->options, | |
626 | vers->tag, vers->date); | |
627 | } | |
628 | freevers_ts (&vers); | |
629 | } | |
630 | dellist (&entries); | |
631 | } | |
632 | ||
633 | /* Don't log "export", just regular "checkouts" */ | |
634 | if (strcmp (command_name, "export") != 0 && !pipeout) | |
635 | history_write ('O', preload_update_dir, (tag ? tag : date), where, | |
636 | repository); | |
637 | ||
638 | /* go ahead and call update now that everything is set */ | |
639 | err += do_update (*pargc - 1, argv + 1, options, tag, date, | |
640 | force_tag_match, local_specified, 1 /* update -d */, | |
641 | aflag, checkout_prune_dirs, pipeout, which, join_rev1, | |
642 | join_rev2, preload_update_dir); | |
643 | free (preload_update_dir); | |
644 | preload_update_dir = oldupdate; | |
645 | return (err); | |
646 | } | |
647 | ||
648 | static char * | |
649 | findslash (start, p) | |
650 | char *start; | |
651 | char *p; | |
652 | { | |
653 | while ((int) p >= (int) start && *p != '/') | |
654 | p--; | |
655 | if ((int) p < (int) start) | |
656 | return (NULL); | |
657 | else | |
658 | return (p); | |
659 | } | |
660 | ||
661 | /* | |
662 | * build all the dirs along the path to dir with CVS subdirs with appropriate | |
663 | * repositories and Entries.Static files | |
664 | */ | |
665 | static int | |
666 | build_dirs_and_chdir (dir, prepath, realdir, sticky) | |
667 | char *dir; | |
668 | char *prepath; | |
669 | char *realdir; | |
670 | int sticky; | |
671 | { | |
672 | FILE *fp; | |
673 | char repository[PATH_MAX]; | |
674 | char path[PATH_MAX]; | |
675 | char path2[PATH_MAX]; | |
676 | char *slash; | |
677 | char *slash2; | |
678 | char *cp; | |
679 | char *cp2; | |
680 | ||
681 | (void) strcpy (path, dir); | |
682 | (void) strcpy (path2, realdir); | |
683 | for (cp = path, cp2 = path2; | |
684 | (slash = index (cp, '/')) != NULL && (slash2 = index (cp2, '/')) != NULL; | |
685 | cp = slash + 1, cp2 = slash2 + 1) | |
686 | { | |
687 | *slash = '\0'; | |
688 | *slash2 = '\0'; | |
689 | (void) mkdir (cp, 0777); | |
690 | if (chdir (cp) < 0) | |
691 | { | |
692 | error (0, errno, "cannot chdir to %s", cp); | |
693 | return (1); | |
694 | } | |
695 | if (!isfile (CVSADM) && !isfile (OCVSADM) && | |
696 | strcmp (command_name, "export") != 0) | |
697 | { | |
698 | (void) sprintf (repository, "%s/%s", prepath, path2); | |
699 | Create_Admin (".", repository, sticky ? (char *) NULL : tag, | |
700 | sticky ? (char *) NULL : date); | |
701 | if (!noexec) | |
702 | { | |
703 | fp = open_file (CVSADM_ENTSTAT, "w+"); | |
704 | if (fclose(fp) == EOF) | |
705 | error(1, errno, "cannot close %s", CVSADM_ENTSTAT); | |
706 | } | |
707 | } | |
708 | *slash = '/'; | |
709 | *slash2 = '/'; | |
710 | } | |
711 | (void) mkdir (cp, 0777); | |
712 | if (chdir (cp) < 0) | |
713 | { | |
714 | error (0, errno, "cannot chdir to %s", cp); | |
715 | return (1); | |
716 | } | |
717 | return (0); | |
718 | } |