Deleted Added
full compact
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
4 *
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
7 *
8 * "import" checks in the vendor release located in the current directory into
9 * the CVS source repository. The CVS vendor branch support is utilized.
10 *
11 * At least three arguments are expected to follow the options:
12 * repository Where the source belongs relative to the CVSROOT
13 * VendorTag Vendor's major tag
14 * VendorReleTag Tag for this particular release
15 *
16 * Additional arguments specify more Vendor Release Tags.
17 *
18 * $FreeBSD: head/contrib/cvs/src/import.c 102843 2002-09-02 05:57:14Z peter $
18 * $FreeBSD: head/contrib/cvs/src/import.c 107487 2002-12-02 03:17:49Z peter $
19 */
20
21#include "cvs.h"
22#include "savecwd.h"
23#include <assert.h>
24
25static char *get_comment PROTO((char *user));
26static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
27 char *vers));
28static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
29 char *targv[]));
30static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]));
31static int import_descend_dir PROTO((char *message, char *dir, char *vtag,
32 int targc, char *targv[]));
33static int process_import_file PROTO((char *message, char *vfile, char *vtag,
34 int targc, char *targv[]));
35static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc,
36 char *targv[], int inattic));
37static void add_log PROTO((int ch, char *fname));
38
39static int repos_len;
40static char *vhead;
41static char *vbranch;
42static FILE *logfp;
43static char *repository;
44static int conflicts;
45static int use_file_modtime;
46static char *keyword_opt = NULL;
47
48static const char *const import_usage[] =
49{
50 "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n",
51 " [-W spec] repository vendor-tag release-tags...\n",
52 "\t-d\tUse the file's modification time as the time of import.\n",
53 "\t-k sub\tSet default RCS keyword substitution mode.\n",
54 "\t-I ign\tMore files to ignore (! to reset).\n",
55 "\t-b bra\tVendor branch id.\n",
56 "\t-m msg\tLog message.\n",
57 "\t-W spec\tWrappers specification line.\n",
58 "(Specify the --help global option for a list of other help options)\n",
59 NULL
60};
61
62int
63import (argc, argv)
64 int argc;
65 char **argv;
66{
67 char *message = NULL;
68 char *tmpfile;
69 char *cp;
70 int i, c, msglen, err;
71 List *ulist;
72 Node *p;
73 struct logfile_info *li;
74
75 if (argc == -1)
76 usage (import_usage);
77
78 ign_setup ();
79 wrap_setup ();
80
81 vbranch = xstrdup (CVSBRANCH);
82 optind = 0;
83 while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1)
84 {
85 switch (c)
86 {
87 case 'Q':
88 case 'q':
89#ifdef SERVER_SUPPORT
90 /* The CVS 1.5 client sends these options (in addition to
91 Global_option requests), so we must ignore them. */
92 if (!server_active)
93#endif
94 error (1, 0,
95 "-q or -Q must be specified before \"%s\"",
96 command_name);
97 break;
98 case 'd':
99#ifdef SERVER_SUPPORT
100 if (server_active)
101 {
102 /* CVS 1.10 and older clients will send this, but it
103 doesn't do any good. So tell the user we can't
104 cope, rather than silently losing. */
105 error (0, 0,
106 "warning: not setting the time of import from the file");
107 error (0, 0, "due to client limitations");
108 }
109#endif
110 use_file_modtime = 1;
111 break;
112 case 'b':
113 free (vbranch);
114 vbranch = xstrdup (optarg);
115 break;
116 case 'm':
117#ifdef FORCE_USE_EDITOR
118 use_editor = 1;
119#else
120 use_editor = 0;
121#endif
122 message = xstrdup(optarg);
123 break;
124 case 'I':
125 ign_add (optarg, 0);
126 break;
127 case 'k':
128 /* RCS_check_kflag returns strings of the form -kxx. We
129 only use it for validation, so we can free the value
130 as soon as it is returned. */
131 free (RCS_check_kflag (optarg));
132 keyword_opt = optarg;
133 break;
134 case 'W':
135 wrap_add (optarg, 0);
136 break;
137 case '?':
138 default:
139 usage (import_usage);
140 break;
141 }
142 }
143 argc -= optind;
144 argv += optind;
145 if (argc < 3)
146 usage (import_usage);
147
148#ifdef SERVER_SUPPORT
149 /* This is for handling the Checkin-time request. It might seem a
150 bit odd to enable the use_file_modtime code even in the case
151 where Checkin-time was not sent for a particular file. The
152 effect is that we use the time of upload, rather than the time
153 when we call RCS_checkin. Since those times are both during
154 CVS's run, that seems OK, and it is easier to implement than
155 putting the "was Checkin-time sent" flag in CVS/Entries or some
156 such place. */
157
158 if (server_active)
159 use_file_modtime = 1;
160#endif
161
162 for (i = 1; i < argc; i++) /* check the tags for validity */
163 {
164 int j;
165
166 RCS_check_tag (argv[i]);
167 for (j = 1; j < i; j++)
168 if (strcmp (argv[j], argv[i]) == 0)
169 error (1, 0, "tag `%s' was specified more than once", argv[i]);
170 }
171
172 /* XXX - this should be a module, not just a pathname */
173 if (! isabsolute (argv[0])
174 && pathname_levels (argv[0]) == 0)
175 {
176 if (current_parsed_root == NULL)
177 {
178 error (0, 0, "missing CVSROOT environment variable\n");
179 error (1, 0, "Set it or specify the '-d' option to %s.",
180 program_name);
181 }
182 repository = xmalloc (strlen (current_parsed_root->directory)
183 + strlen (argv[0])
184 + 2);
185 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
186 repos_len = strlen (current_parsed_root->directory);
187 }
188 else
189 {
190 /* It is somewhere between a security hole and "unexpected" to
191 let the client start mucking around outside the cvsroot
192 (wouldn't get the right CVSROOT configuration, &c). */
193 error (1, 0, "directory %s not relative within the repository",
194 argv[0]);
195 }
196
197 /*
198 * Consistency checks on the specified vendor branch. It must be
199 * composed of only numbers and dots ('.'). Also, for now we only
200 * support branching to a single level, so the specified vendor branch
201 * must only have two dots in it (like "1.1.1").
202 */
203 for (cp = vbranch; *cp != '\0'; cp++)
204 if (!isdigit ((unsigned char) *cp) && *cp != '.')
205 error (1, 0, "%s is not a numeric branch", vbranch);
206 if (numdots (vbranch) != 2)
207 error (1, 0, "Only branches with two dots are supported: %s", vbranch);
208 vhead = xstrdup (vbranch);
209 cp = strrchr (vhead, '.');
210 *cp = '\0';
211
212#ifdef CLIENT_SUPPORT
213 if (current_parsed_root->isremote)
214 {
215 /* For rationale behind calling start_server before do_editor, see
216 commit.c */
217 start_server ();
218 }
219#endif
220
221 if (use_editor)
221 if (
222#ifdef SERVER_SUPPORT
223 !server_active &&
224#endif
225 use_editor)
226 {
227 do_editor ((char *) NULL, &message,
228#ifdef CLIENT_SUPPORT
229 current_parsed_root->isremote ? (char *) NULL :
230#endif
231 repository,
232 (List *) NULL);
233 }
234 do_verify (&message, repository);
235 msglen = message == NULL ? 0 : strlen (message);
236 if (msglen == 0 || message[msglen - 1] != '\n')
237 {
238 char *nm = xmalloc (msglen + 2);
239 *nm = '\0';
240 if (message != NULL)
241 {
242 (void) strcpy (nm, message);
243 free (message);
244 }
245 (void) strcat (nm + msglen, "\n");
246 message = nm;
247 }
248
249#ifdef CLIENT_SUPPORT
250 if (current_parsed_root->isremote)
251 {
252 int err;
253
254 if (vbranch[0] != '\0')
255 option_with_arg ("-b", vbranch);
252 if (message)
253 option_with_arg ("-m", message);
256 option_with_arg ("-m", message ? message : "");
257 if (keyword_opt != NULL)
258 option_with_arg ("-k", keyword_opt);
259 /* The only ignore processing which takes place on the server side
260 is the CVSROOT/cvsignore file. But if the user specified -I !,
261 the documented behavior is to not process said file. */
262 if (ign_inhibit_server)
263 {
264 send_arg ("-I");
265 send_arg ("!");
266 }
267 wrap_send ();
268
269 {
270 int i;
271 for (i = 0; i < argc; ++i)
272 send_arg (argv[i]);
273 }
274
275 logfp = stdin;
276 client_import_setup (repository);
277 err = import_descend (message, argv[1], argc - 2, argv + 2);
278 client_import_done ();
279 if (message)
280 free (message);
281 free (repository);
282 free (vbranch);
283 free (vhead);
284 send_to_server ("import\012", 0);
285 err += get_responses_and_close ();
286 return err;
287 }
288#endif
289
290 if (!safe_location ( NULL ))
291 {
292 error (1, 0, "attempt to import the repository");
293 }
294
295 /*
296 * Make all newly created directories writable. Should really use a more
297 * sophisticated security mechanism here.
298 */
299 (void) umask (cvsumask);
300 make_directories (repository);
301
302 /* Create the logfile that will be logged upon completion */
303 if ((logfp = cvs_temp_file (&tmpfile)) == NULL)
304 error (1, errno, "cannot create temporary file `%s'", tmpfile);
305 /* On systems where we can unlink an open file, do so, so it will go
306 away no matter how we exit. FIXME-maybe: Should be checking for
307 errors but I'm not sure which error(s) we get if we are on a system
308 where one can't unlink open files. */
309 (void) CVS_UNLINK (tmpfile);
310 (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
311 (void) fprintf (logfp, "Release Tags:\t");
312 for (i = 2; i < argc; i++)
313 (void) fprintf (logfp, "%s\n\t\t", argv[i]);
314 (void) fprintf (logfp, "\n");
315
316 /* Just Do It. */
317 err = import_descend (message, argv[1], argc - 2, argv + 2);
318 if (conflicts)
319 {
320 if (!really_quiet)
321 {
322 char buf[20];
323
324 cvs_output_tagged ("+importmergecmd", NULL);
325 cvs_output_tagged ("newline", NULL);
326 sprintf (buf, "%d", conflicts);
327 cvs_output_tagged ("conflicts", buf);
328 cvs_output_tagged ("text", " conflicts created by this import.");
329 cvs_output_tagged ("newline", NULL);
330 cvs_output_tagged ("text",
331 "Use the following command to help the merge:");
332 cvs_output_tagged ("newline", NULL);
333 cvs_output_tagged ("newline", NULL);
334 cvs_output_tagged ("text", "\t");
335 cvs_output_tagged ("text", program_name);
336 if (CVSroot_cmdline != NULL)
337 {
338 cvs_output_tagged ("text", " -d ");
339 cvs_output_tagged ("text", CVSroot_cmdline);
340 }
341 cvs_output_tagged ("text", " checkout -j");
342 cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
343 cvs_output_tagged ("text", " -j");
344 cvs_output_tagged ("mergetag2", argv[2]);
345 cvs_output_tagged ("text", " ");
346 cvs_output_tagged ("repository", argv[0]);
347 cvs_output_tagged ("newline", NULL);
348 cvs_output_tagged ("newline", NULL);
349 cvs_output_tagged ("-importmergecmd", NULL);
350 }
351
352 /* FIXME: I'm not sure whether we need to put this information
353 into the loginfo. If we do, then note that it does not
354 report any required -d option. There is no particularly
355 clean way to tell the server about the -d option used by
356 the client. */
357 (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
358 conflicts);
359 (void) fprintf (logfp,
360 "Use the following command to help the merge:\n\n");
361 (void) fprintf (logfp, "\t%s checkout ", program_name);
362 (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
363 argv[1], argv[1], argv[0]);
364 }
365 else
366 {
367 if (!really_quiet)
368 cvs_output ("\nNo conflicts created by this import\n\n", 0);
369 (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
370 }
371
372 /*
373 * Write out the logfile and clean up.
374 */
375 ulist = getlist ();
376 p = getnode ();
377 p->type = UPDATE;
378 p->delproc = update_delproc;
379 p->key = xstrdup ("- Imported sources");
380 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
381 li->type = T_TITLE;
382 li->tag = xstrdup (vbranch);
383 li->rev_old = li->rev_new = NULL;
384 p->data = (char *) li;
385 (void) addnode (ulist, p);
386 Update_Logfile (repository, message, logfp, ulist);
387 dellist (&ulist);
388 if (fclose (logfp) < 0)
389 error (0, errno, "error closing %s", tmpfile);
390
391 /* Make sure the temporary file goes away, even on systems that don't let
392 you delete a file that's in use. */
393 if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
394 error (0, errno, "cannot remove %s", tmpfile);
395 free (tmpfile);
396
397 if (message)
398 free (message);
399 free (repository);
400 free (vbranch);
401 free (vhead);
402
403 return (err);
404}
405
406/* Process all the files in ".", then descend into other directories.
407 Returns 0 for success, or >0 on error (in which case a message
408 will have been printed). */
409static int
410import_descend (message, vtag, targc, targv)
411 char *message;
412 char *vtag;
413 int targc;
414 char *targv[];
415{
416 DIR *dirp;
417 struct dirent *dp;
418 int err = 0;
419 List *dirlist = NULL;
420
421 /* first, load up any per-directory ignore lists */
422 ign_add_file (CVSDOTIGNORE, 1);
423 wrap_add_file (CVSDOTWRAPPER, 1);
424
425 if ((dirp = CVS_OPENDIR (".")) == NULL)
426 {
427 error (0, errno, "cannot open directory");
428 err++;
429 }
430 else
431 {
432 errno = 0;
433 while ((dp = CVS_READDIR (dirp)) != NULL)
434 {
435 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
436 goto one_more_time_boys;
437#ifdef SERVER_SUPPORT
438 /* CVS directories are created in the temp directory by
439 server.c because it doesn't special-case import. So
440 don't print a message about them, regardless of -I!. */
441 if (server_active && strcmp (dp->d_name, CVSADM) == 0)
442 goto one_more_time_boys;
443#endif
444 if (ign_name (dp->d_name))
445 {
446 add_log ('I', dp->d_name);
447 goto one_more_time_boys;
448 }
449
450 if (
451#ifdef DT_DIR
452 (dp->d_type == DT_DIR
453 || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
454#else
455 isdir (dp->d_name)
456#endif
457 && !wrap_name_has (dp->d_name, WRAP_TOCVS)
458 )
459 {
460 Node *n;
461
462 if (dirlist == NULL)
463 dirlist = getlist();
464
465 n = getnode();
466 n->key = xstrdup (dp->d_name);
467 addnode(dirlist, n);
468 }
469 else if (
470#ifdef DT_DIR
471 dp->d_type == DT_LNK
472 || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
473#else
474 islink (dp->d_name)
475#endif
476 )
477 {
478 add_log ('L', dp->d_name);
479 err++;
480 }
481 else
482 {
483#ifdef CLIENT_SUPPORT
484 if (current_parsed_root->isremote)
485 err += client_process_import_file (message, dp->d_name,
486 vtag, targc, targv,
487 repository,
488 keyword_opt != NULL &&
489 keyword_opt[0] == 'b',
490 use_file_modtime);
491 else
492#endif
493 err += process_import_file (message, dp->d_name,
494 vtag, targc, targv);
495 }
496 one_more_time_boys:
497 errno = 0;
498 }
499 if (errno != 0)
500 {
501 error (0, errno, "cannot read directory");
502 ++err;
503 }
504 (void) CVS_CLOSEDIR (dirp);
505 }
506
507 if (dirlist != NULL)
508 {
509 Node *head, *p;
510
511 head = dirlist->list;
512 for (p = head->next; p != head; p = p->next)
513 {
514 err += import_descend_dir (message, p->key, vtag, targc, targv);
515 }
516
517 dellist(&dirlist);
518 }
519
520 return (err);
521}
522
523/*
524 * Process the argument import file.
525 */
526static int
527process_import_file (message, vfile, vtag, targc, targv)
528 char *message;
529 char *vfile;
530 char *vtag;
531 int targc;
532 char *targv[];
533{
534 char *rcs;
535 int inattic = 0;
536
537 rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT)
538 + 5);
539 (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
540 if (!isfile (rcs))
541 {
542 char *attic_name;
543
544 attic_name = xmalloc (strlen (repository) + strlen (vfile) +
545 sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
546 (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
547 vfile, RCSEXT);
548 if (!isfile (attic_name))
549 {
550 int retval;
551 char *free_opt = NULL;
552 char *our_opt = keyword_opt;
553
554 free (attic_name);
555 /*
556 * A new import source file; it doesn't exist as a ,v within the
557 * repository nor in the Attic -- create it anew.
558 */
559 add_log ('N', vfile);
560
561#ifdef SERVER_SUPPORT
562 /* The most reliable information on whether the file is binary
563 is what the client told us. That is because if the client had
564 the wrong idea about binaryness, it corrupted the file, so
565 we might as well believe the client. */
566 if (server_active)
567 {
568 Node *node;
569 List *entries;
570
571 /* Reading all the entries for each file is fairly silly, and
572 probably slow. But I am too lazy at the moment to do
573 anything else. */
574 entries = Entries_Open (0, NULL);
575 node = findnode_fn (entries, vfile);
576 if (node != NULL)
577 {
578 Entnode *entdata = (Entnode *) node->data;
579 if (entdata->type == ENT_FILE)
580 {
581 assert (entdata->options[0] == '-'
582 && entdata->options[1] == 'k');
583 our_opt = xstrdup (entdata->options + 2);
584 free_opt = our_opt;
585 }
586 }
587 Entries_Close (entries);
588 }
589#endif
590
591 retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
592 vbranch, vtag, targc, targv,
593 NULL, 0, logfp);
594 if (free_opt != NULL)
595 free (free_opt);
596 free (rcs);
597 return retval;
598 }
599 free (attic_name);
600 inattic = 1;
601 }
602
603 free (rcs);
604 /*
605 * an rcs file exists. have to do things the official, slow, way.
606 */
607 return (update_rcs_file (message, vfile, vtag, targc, targv, inattic));
608}
609
610/*
611 * The RCS file exists; update it by adding the new import file to the
612 * (possibly already existing) vendor branch.
613 */
614static int
615update_rcs_file (message, vfile, vtag, targc, targv, inattic)
616 char *message;
617 char *vfile;
618 char *vtag;
619 int targc;
620 char *targv[];
621 int inattic;
622{
623 Vers_TS *vers;
624 int letter;
625 char *tocvsPath;
626 char *expand;
627 struct file_info finfo;
628
629 memset (&finfo, 0, sizeof finfo);
630 finfo.file = vfile;
631 /* Not used, so don't worry about it. */
632 finfo.update_dir = NULL;
633 finfo.fullname = finfo.file;
634 finfo.repository = repository;
635 finfo.entries = NULL;
636 finfo.rcs = NULL;
637 vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL,
638 1, 0);
639 if (vers->vn_rcs != NULL
640 && !RCS_isdead(vers->srcfile, vers->vn_rcs))
641 {
642 int different;
643
644 /*
645 * The rcs file does have a revision on the vendor branch. Compare
646 * this revision with the import file; if they match exactly, there
647 * is no need to install the new import file as a new revision to the
648 * branch. Just tag the revision with the new import tags.
649 *
650 * This is to try to cut down the number of "C" conflict messages for
651 * locally modified import source files.
652 */
653 tocvsPath = wrap_tocvs_process_file (vfile);
654 /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
655 not NULL? */
656 expand = vers->srcfile->expand != NULL &&
657 vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
658 different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, expand, vfile);
659 if (tocvsPath)
660 if (unlink_file_dir (tocvsPath) < 0)
661 error (0, errno, "cannot remove %s", tocvsPath);
662
663 if (!different)
664 {
665 int retval = 0;
666
667 /*
668 * The two files are identical. Just update the tags, print the
669 * "U", signifying that the file has changed, but needs no
670 * attention, and we're done.
671 */
672 if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
673 retval = 1;
674 add_log ('U', vfile);
675 freevers_ts (&vers);
676 return (retval);
677 }
678 }
679
680 /* We may have failed to parse the RCS file; check just in case */
681 if (vers->srcfile == NULL ||
682 add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
683 add_tags (vers->srcfile, vfile, vtag, targc, targv))
684 {
685 freevers_ts (&vers);
686 return (1);
687 }
688
689 if (vers->srcfile->branch == NULL || inattic ||
690 strcmp (vers->srcfile->branch, vbranch) != 0)
691 {
692 conflicts++;
693 letter = 'C';
694 }
695 else
696 letter = 'U';
697 add_log (letter, vfile);
698
699 freevers_ts (&vers);
700 return (0);
701}
702
703/*
704 * Add the revision to the vendor branch
705 */
706static int
707add_rev (message, rcs, vfile, vers)
708 char *message;
709 RCSNode *rcs;
710 char *vfile;
711 char *vers;
712{
713 int locked, status, ierrno;
714 char *tocvsPath;
715
716 if (noexec)
717 return (0);
718
719 locked = 0;
720 if (vers != NULL)
721 {
722 /* Before RCS_lock existed, we were directing stdout, as well as
723 stderr, from the RCS command, to DEVNULL. I wouldn't guess that
724 was necessary, but I don't know for sure. */
725 /* Earlier versions of this function printed a `fork failed' error
726 when RCS_lock returned an error code. That's not appropriate
727 now that RCS_lock is librarified, but should the error text be
728 preserved? */
729 if (RCS_lock (rcs, vbranch, 1) != 0)
730 return 1;
731 locked = 1;
732 RCS_rewrite (rcs, NULL, NULL);
733 }
734 tocvsPath = wrap_tocvs_process_file (vfile);
735
736 status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
737 message, vbranch,
738 (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
739 | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
740 ierrno = errno;
741
742 if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
743 error (0, errno, "cannot remove %s", tocvsPath);
744
745 if (status)
746 {
747 if (!noexec)
748 {
749 fperrmsg (logfp, 0, status == -1 ? ierrno : 0,
750 "ERROR: Check-in of %s failed", rcs->path);
751 error (0, status == -1 ? ierrno : 0,
752 "ERROR: Check-in of %s failed", rcs->path);
753 }
754 if (locked)
755 {
756 (void) RCS_unlock(rcs, vbranch, 0);
757 RCS_rewrite (rcs, NULL, NULL);
758 }
759 return (1);
760 }
761 return (0);
762}
763
764/*
765 * Add the vendor branch tag and all the specified import release tags to the
766 * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
767 * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
768 * 1.1.1.2, ...).
769 */
770static int
771add_tags (rcs, vfile, vtag, targc, targv)
772 RCSNode *rcs;
773 char *vfile;
774 char *vtag;
775 int targc;
776 char *targv[];
777{
778 int i, ierrno;
779 Vers_TS *vers;
780 int retcode = 0;
781 struct file_info finfo;
782
783 if (noexec)
784 return (0);
785
786 if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
787 {
788 ierrno = errno;
789 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
790 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
791 error (0, retcode == -1 ? ierrno : 0,
792 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
793 return (1);
794 }
795 RCS_rewrite (rcs, NULL, NULL);
796
797 memset (&finfo, 0, sizeof finfo);
798 finfo.file = vfile;
799 /* Not used, so don't worry about it. */
800 finfo.update_dir = NULL;
801 finfo.fullname = finfo.file;
802 finfo.repository = repository;
803 finfo.entries = NULL;
804 finfo.rcs = NULL;
805 vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
806 for (i = 0; i < targc; i++)
807 {
808 if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
809 RCS_rewrite (rcs, NULL, NULL);
810 else
811 {
812 ierrno = errno;
813 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
814 "WARNING: Couldn't add tag %s to %s", targv[i],
815 rcs->path);
816 error (0, retcode == -1 ? ierrno : 0,
817 "WARNING: Couldn't add tag %s to %s", targv[i],
818 rcs->path);
819 }
820 }
821 freevers_ts (&vers);
822 return (0);
823}
824
825/*
826 * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
827 */
828struct compair
829{
830 char *suffix, *comlead;
831};
832
833static const struct compair comtable[] =
834{
835
836/*
837 * comtable pairs each filename suffix with a comment leader. The comment
838 * leader is placed before each line generated by the $Log keyword. This
839 * table is used to guess the proper comment leader from the working file's
840 * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
841 * languages without multiline comments; for others they are optional.
842 *
843 * I believe that the comment leader is unused if you are using RCS 5.7, which
844 * decides what leader to use based on the text surrounding the $Log keyword
845 * rather than a specified comment leader.
846 */
847 {"a", "-- "}, /* Ada */
848 {"ada", "-- "},
849 {"adb", "-- "},
850 {"asm", ";; "}, /* assembler (MS-DOS) */
851 {"ads", "-- "}, /* Ada */
852 {"bas", "' "}, /* Visual Basic code */
853 {"bat", ":: "}, /* batch (MS-DOS) */
854 {"body", "-- "}, /* Ada */
855 {"c", " * "}, /* C */
856 {"c++", "// "}, /* C++ in all its infinite guises */
857 {"cc", "// "},
858 {"cpp", "// "},
859 {"cxx", "// "},
860 {"m", "// "}, /* Objective-C */
861 {"cl", ";;; "}, /* Common Lisp */
862 {"cmd", ":: "}, /* command (OS/2) */
863 {"cmf", "c "}, /* CM Fortran */
864 {"cs", " * "}, /* C* */
865 {"csh", "# "}, /* shell */
866 {"dlg", " * "}, /* MS Windows dialog file */
867 {"e", "# "}, /* efl */
868 {"epsf", "% "}, /* encapsulated postscript */
869 {"epsi", "% "}, /* encapsulated postscript */
870 {"el", "; "}, /* Emacs Lisp */
871 {"f", "c "}, /* Fortran */
872 {"for", "c "},
873 {"frm", "' "}, /* Visual Basic form */
874 {"h", " * "}, /* C-header */
875 {"hh", "// "}, /* C++ header */
876 {"hpp", "// "},
877 {"hxx", "// "},
878 {"in", "# "}, /* for Makefile.in */
879 {"l", " * "}, /* lex (conflict between lex and
880 * franzlisp) */
881 {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
882 * VMS, etc) */
883 {"mak", "# "}, /* makefile, e.g. Visual C++ */
884 {"me", ".\\\" "}, /* me-macros t/nroff */
885 {"ml", "; "}, /* mocklisp */
886 {"mm", ".\\\" "}, /* mm-macros t/nroff */
887 {"ms", ".\\\" "}, /* ms-macros t/nroff */
888 {"man", ".\\\" "}, /* man-macros t/nroff */
889 {"1", ".\\\" "}, /* feeble attempt at man pages... */
890 {"2", ".\\\" "},
891 {"3", ".\\\" "},
892 {"4", ".\\\" "},
893 {"5", ".\\\" "},
894 {"6", ".\\\" "},
895 {"7", ".\\\" "},
896 {"8", ".\\\" "},
897 {"9", ".\\\" "},
898 {"p", " * "}, /* pascal */
899 {"pas", " * "},
900 {"pl", "# "}, /* perl (conflict with Prolog) */
901 {"ps", "% "}, /* postscript */
902 {"psw", "% "}, /* postscript wrap */
903 {"pswm", "% "}, /* postscript wrap */
904 {"r", "# "}, /* ratfor */
905 {"rc", " * "}, /* Microsoft Windows resource file */
906 {"red", "% "}, /* psl/rlisp */
907#ifdef sparc
908 {"s", "! "}, /* assembler */
909#endif
910#ifdef mc68000
911 {"s", "| "}, /* assembler */
912#endif
913#ifdef pdp11
914 {"s", "/ "}, /* assembler */
915#endif
916#ifdef vax
917 {"s", "# "}, /* assembler */
918#endif
919#ifdef __ksr__
920 {"s", "# "}, /* assembler */
921 {"S", "# "}, /* Macro assembler */
922#endif
923 {"sh", "# "}, /* shell */
924 {"sl", "% "}, /* psl */
925 {"spec", "-- "}, /* Ada */
926 {"tex", "% "}, /* tex */
927 {"y", " * "}, /* yacc */
928 {"ye", " * "}, /* yacc-efl */
929 {"yr", " * "}, /* yacc-ratfor */
930 {"", "# "}, /* default for empty suffix */
931 {NULL, "# "} /* default for unknown suffix; */
932/* must always be last */
933};
934
935static char *
936get_comment (user)
937 char *user;
938{
939 char *cp, *suffix;
940 char *suffix_path;
941 int i;
942 char *retval;
943
944 suffix_path = xmalloc (strlen (user) + 5);
945 cp = strrchr (user, '.');
946 if (cp != NULL)
947 {
948 cp++;
949
950 /*
951 * Convert to lower-case, since we are not concerned about the
952 * case-ness of the suffix.
953 */
954 (void) strcpy (suffix_path, cp);
955 for (cp = suffix_path; *cp; cp++)
956 if (isupper ((unsigned char) *cp))
957 *cp = tolower (*cp);
958 suffix = suffix_path;
959 }
960 else
961 suffix = ""; /* will use the default */
962 for (i = 0;; i++)
963 {
964 if (comtable[i].suffix == NULL)
965 {
966 /* Default. Note we'll always hit this case before we
967 ever return NULL. */
968 retval = comtable[i].comlead;
969 break;
970 }
971 if (strcmp (suffix, comtable[i].suffix) == 0)
972 {
973 retval = comtable[i].comlead;
974 break;
975 }
976 }
977 free (suffix_path);
978 return retval;
979}
980
981/* Create a new RCS file from scratch.
982
983 This probably should be moved to rcs.c now that it is called from
984 places outside import.c.
985
986 Return value is 0 for success, or nonzero for failure (in which
987 case an error message will have already been printed). */
988int
989add_rcs_file (message, rcs, user, add_vhead, key_opt,
990 add_vbranch, vtag, targc, targv,
991 desctext, desclen, add_logfp)
992 /* Log message for the addition. Not used if add_vhead == NULL. */
993 char *message;
994 /* Filename of the RCS file to create. */
995 char *rcs;
996 /* Filename of the file to serve as the contents of the initial
997 revision. Even if add_vhead is NULL, we use this to determine
998 the modes to give the new RCS file. */
999 char *user;
1000
1001 /* Revision number of head that we are adding. Normally 1.1 but
1002 could be another revision as long as ADD_VBRANCH is a branch
1003 from it. If NULL, then just add an empty file without any
1004 revisions (similar to the one created by "rcs -i"). */
1005 char *add_vhead;
1006
1007 /* Keyword expansion mode, e.g., "b" for binary. NULL means the
1008 default behavior. */
1009 char *key_opt;
1010
1011 /* Vendor branch to import to, or NULL if none. If non-NULL, then
1012 vtag should also be non-NULL. */
1013 char *add_vbranch;
1014 char *vtag;
1015 int targc;
1016 char *targv[];
1017
1018 /* If non-NULL, description for the file. If NULL, the description
1019 will be empty. */
1020 char *desctext;
1021 size_t desclen;
1022
1023 /* Write errors to here as well as via error (), or NULL if we should
1024 use only error (). */
1025 FILE *add_logfp;
1026{
1027 FILE *fprcs, *fpuser;
1028 struct stat sb;
1029 struct tm *ftm;
1030 time_t now;
1031 char altdate1[MAXDATELEN];
1032 char *author;
1033 int i, ierrno, err = 0;
1034 mode_t mode;
1035 char *tocvsPath;
1036 char *userfile;
1037 char *local_opt = key_opt;
1038 char *free_opt = NULL;
1039 mode_t file_type;
1040
1041 if (noexec)
1042 return (0);
1043
1044 /* Note that as the code stands now, the -k option overrides any
1045 settings in wrappers (whether CVSROOT/cvswrappers, -W, or
1046 whatever). Some have suggested this should be the other way
1047 around. As far as I know the documentation doesn't say one way
1048 or the other. Before making a change of this sort, should think
1049 about what is best, document it (in cvs.texinfo and NEWS), &c. */
1050
1051 if (local_opt == NULL)
1052 {
1053 if (wrap_name_has (user, WRAP_RCSOPTION))
1054 {
1055 local_opt = free_opt = wrap_rcsoption (user, 0);
1056 }
1057 }
1058
1059 tocvsPath = wrap_tocvs_process_file (user);
1060 userfile = (tocvsPath == NULL ? user : tocvsPath);
1061
1062 /* Opening in text mode is probably never the right thing for the
1063 server (because the protocol encodes text files in a fashion
1064 which does not depend on what the client or server OS is, as
1065 documented in cvsclient.texi), but as long as the server just
1066 runs on unix it is a moot point. */
1067
1068 /* If PreservePermissions is set, then make sure that the file
1069 is a plain file before trying to open it. Longstanding (although
1070 often unpopular) CVS behavior has been to follow symlinks, so we
1071 maintain that behavior if PreservePermissions is not on.
1072
1073 NOTE: this error message used to be `cannot fstat', but is now
1074 `cannot lstat'. I don't see a way around this, since we must
1075 stat the file before opening it. -twp */
1076
1077 if (CVS_LSTAT (userfile, &sb) < 0)
1078 {
1079 /* not fatal, continue import */
1080 if (add_logfp != NULL)
1081 fperrmsg (add_logfp, 0, errno,
1082 "ERROR: cannot lstat file %s", userfile);
1083 error (0, errno, "cannot lstat file %s", userfile);
1084 goto read_error;
1085 }
1086 file_type = sb.st_mode & S_IFMT;
1087
1088 fpuser = NULL;
1089 if (!preserve_perms || file_type == S_IFREG)
1090 {
1091 fpuser = CVS_FOPEN (userfile,
1092 ((local_opt != NULL && strcmp (local_opt, "b") == 0)
1093 ? "rb"
1094 : "r")
1095 );
1096 if (fpuser == NULL)
1097 {
1098 /* not fatal, continue import */
1099 if (add_logfp != NULL)
1100 fperrmsg (add_logfp, 0, errno,
1101 "ERROR: cannot read file %s", userfile);
1102 error (0, errno, "ERROR: cannot read file %s", userfile);
1103 goto read_error;
1104 }
1105 }
1106
1107 fprcs = CVS_FOPEN (rcs, "w+b");
1108 if (fprcs == NULL)
1109 {
1110 ierrno = errno;
1111 goto write_error_noclose;
1112 }
1113
1114 /*
1115 * putadmin()
1116 */
1117 if (add_vhead != NULL)
1118 {
1119 if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
1120 goto write_error;
1121 }
1122 else
1123 {
1124 if (fprintf (fprcs, "head ;\012") < 0)
1125 goto write_error;
1126 }
1127
1128 if (add_vbranch != NULL)
1129 {
1130 if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
1131 goto write_error;
1132 }
1133 if (fprintf (fprcs, "access ;\012") < 0 ||
1134 fprintf (fprcs, "symbols ") < 0)
1135 {
1136 goto write_error;
1137 }
1138
1139 for (i = targc - 1; i >= 0; i--)
1140 {
1141 /* RCS writes the symbols backwards */
1142 assert (add_vbranch != NULL);
1143 if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
1144 goto write_error;
1145 }
1146
1147 if (add_vbranch != NULL)
1148 {
1149 if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
1150 goto write_error;
1151 }
1152 if (fprintf (fprcs, ";\012") < 0)
1153 goto write_error;
1154
1155 if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
1156 /* XXX - make sure @@ processing works in the RCS file */
1157 fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
1158 {
1159 goto write_error;
1160 }
1161
1162 if (local_opt != NULL && strcmp (local_opt, "kv") != 0)
1163 {
1164 if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0)
1165 {
1166 goto write_error;
1167 }
1168 }
1169
1170 if (fprintf (fprcs, "\012") < 0)
1171 goto write_error;
1172
1173 /* Write the revision(s), with the date and author and so on
1174 (that is "delta" rather than "deltatext" from rcsfile(5)). */
1175 if (add_vhead != NULL)
1176 {
1177 if (use_file_modtime)
1178 now = sb.st_mtime;
1179 else
1180 (void) time (&now);
1181 ftm = gmtime (&now);
1182 (void) sprintf (altdate1, DATEFORM,
1183 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1184 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1185 ftm->tm_min, ftm->tm_sec);
1186 author = getcaller ();
1187
1188 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1189 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1190 altdate1, author) < 0)
1191 goto write_error;
1192
1193 if (fprintf (fprcs, "branches") < 0)
1194 goto write_error;
1195 if (add_vbranch != NULL)
1196 {
1197 if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
1198 goto write_error;
1199 }
1200 if (fprintf (fprcs, ";\012") < 0)
1201 goto write_error;
1202
1203 if (fprintf (fprcs, "next ;\012") < 0)
1204 goto write_error;
1205
1206#ifdef PRESERVE_PERMISSIONS_SUPPORT
1207 /* Store initial permissions if necessary. */
1208 if (preserve_perms)
1209 {
1210 if (file_type == S_IFLNK)
1211 {
1212 char *link = xreadlink (userfile);
1213 if (fprintf (fprcs, "symlink\t@") < 0 ||
1214 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1215 fprintf (fprcs, "@;\012") < 0)
1216 goto write_error;
1217 free (link);
1218 }
1219 else
1220 {
1221 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
1222 goto write_error;
1223 if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
1224 goto write_error;
1225 if (fprintf (fprcs, "permissions\t%o;\012",
1226 sb.st_mode & 07777) < 0)
1227 goto write_error;
1228 switch (file_type)
1229 {
1230 case S_IFREG: break;
1231 case S_IFCHR:
1232 case S_IFBLK:
1230#ifdef HAVE_ST_RDEV
1233#ifdef HAVE_STRUCT_STAT_ST_RDEV
1234 if (fprintf (fprcs, "special\t%s %lu;\012",
1235 (file_type == S_IFCHR
1236 ? "character"
1237 : "block"),
1238 (unsigned long) sb.st_rdev) < 0)
1239 goto write_error;
1240#else
1241 error (0, 0,
1242"can't import %s: unable to import device files on this system",
1243userfile);
1244#endif
1245 break;
1246 default:
1247 error (0, 0,
1248 "can't import %s: unknown kind of special file",
1249 userfile);
1250 }
1251 }
1252 }
1253#endif
1254
1255 if (add_vbranch != NULL)
1256 {
1257 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1258 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1259 altdate1, author) < 0 ||
1260 fprintf (fprcs, "branches ;\012") < 0 ||
1261 fprintf (fprcs, "next ;\012") < 0)
1262 goto write_error;
1263
1264#ifdef PRESERVE_PERMISSIONS_SUPPORT
1265 /* Store initial permissions if necessary. */
1266 if (preserve_perms)
1267 {
1268 if (file_type == S_IFLNK)
1269 {
1270 char *link = xreadlink (userfile);
1271 if (fprintf (fprcs, "symlink\t@") < 0 ||
1272 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1273 fprintf (fprcs, "@;\012") < 0)
1274 goto write_error;
1275 free (link);
1276 }
1277 else
1278 {
1279 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
1280 fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
1281 fprintf (fprcs, "permissions\t%o;\012",
1282 sb.st_mode & 07777) < 0)
1283 goto write_error;
1284
1285 switch (file_type)
1286 {
1287 case S_IFREG: break;
1288 case S_IFCHR:
1289 case S_IFBLK:
1287#ifdef HAVE_ST_RDEV
1290#ifdef HAVE_STRUCT_STAT_ST_RDEV
1291 if (fprintf (fprcs, "special\t%s %lu;\012",
1292 (file_type == S_IFCHR
1293 ? "character"
1294 : "block"),
1295 (unsigned long) sb.st_rdev) < 0)
1296 goto write_error;
1297#else
1298 error (0, 0,
1299"can't import %s: unable to import device files on this system",
1300userfile);
1301#endif
1302 break;
1303 default:
1304 error (0, 0,
1305 "cannot import %s: special file of unknown type",
1306 userfile);
1307 }
1308 }
1309 }
1310#endif
1311
1312 if (fprintf (fprcs, "\012") < 0)
1313 goto write_error;
1314 }
1315 }
1316
1317 /* Now write the description (possibly empty). */
1318 if (fprintf (fprcs, "\012desc\012") < 0 ||
1319 fprintf (fprcs, "@") < 0)
1320 goto write_error;
1321 if (desctext != NULL)
1322 {
1323 /* The use of off_t not size_t for the second argument is very
1324 strange, since we are dealing with something which definitely
1325 fits in memory. */
1326 if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
1327 goto write_error;
1328 }
1329 if (fprintf (fprcs, "@\012\012\012") < 0)
1330 goto write_error;
1331
1332 /* Now write the log messages and contents for the revision(s) (that
1333 is, "deltatext" rather than "delta" from rcsfile(5)). */
1334 if (add_vhead != NULL)
1335 {
1336 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1337 fprintf (fprcs, "log\012@") < 0)
1338 goto write_error;
1339 if (add_vbranch != NULL)
1340 {
1341 /* We are going to put the log message in the revision on the
1342 branch. So putting it here too seems kind of redundant, I
1343 guess (and that is what CVS has always done, anyway). */
1344 if (fprintf (fprcs, "Initial revision\012") < 0)
1345 goto write_error;
1346 }
1347 else
1348 {
1349 if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
1350 goto write_error;
1351 }
1352 if (fprintf (fprcs, "@\012") < 0 ||
1353 fprintf (fprcs, "text\012@") < 0)
1354 {
1355 goto write_error;
1356 }
1357
1358 /* Now copy over the contents of the file, expanding at signs.
1359 If preserve_perms is set, do this only for regular files. */
1360 if (!preserve_perms || file_type == S_IFREG)
1361 {
1362 char buf[8192];
1363 unsigned int len;
1364
1365 while (1)
1366 {
1367 len = fread (buf, 1, sizeof buf, fpuser);
1368 if (len == 0)
1369 {
1370 if (ferror (fpuser))
1371 error (1, errno, "cannot read file %s for copying",
1372 user);
1373 break;
1374 }
1375 if (expand_at_signs (buf, len, fprcs) < 0)
1376 goto write_error;
1377 }
1378 }
1379 if (fprintf (fprcs, "@\012\012") < 0)
1380 goto write_error;
1381 if (add_vbranch != NULL)
1382 {
1383 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1384 fprintf (fprcs, "log\012@") < 0 ||
1385 expand_at_signs (message,
1386 (off_t) strlen (message), fprcs) < 0 ||
1387 fprintf (fprcs, "@\012text\012") < 0 ||
1388 fprintf (fprcs, "@@\012") < 0)
1389 goto write_error;
1390 }
1391 }
1392
1393 if (fclose (fprcs) == EOF)
1394 {
1395 ierrno = errno;
1396 goto write_error_noclose;
1397 }
1398 /* Close fpuser only if we opened it to begin with. */
1399 if (fpuser != NULL)
1400 {
1401 if (fclose (fpuser) < 0)
1402 error (0, errno, "cannot close %s", user);
1403 }
1404
1405 /*
1406 * Fix the modes on the RCS files. The user modes of the original
1407 * user file are propagated to the group and other modes as allowed
1408 * by the repository umask, except that all write permissions are
1409 * turned off.
1410 */
1411 mode = (sb.st_mode |
1412 (sb.st_mode & S_IRWXU) >> 3 |
1413 (sb.st_mode & S_IRWXU) >> 6) &
1414 ~cvsumask &
1415 ~(S_IWRITE | S_IWGRP | S_IWOTH);
1416 if (chmod (rcs, mode) < 0)
1417 {
1418 ierrno = errno;
1419 if (add_logfp != NULL)
1420 fperrmsg (add_logfp, 0, ierrno,
1421 "WARNING: cannot change mode of file %s", rcs);
1422 error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
1423 err++;
1424 }
1425 if (tocvsPath)
1426 if (unlink_file_dir (tocvsPath) < 0)
1427 error (0, errno, "cannot remove %s", tocvsPath);
1428 if (free_opt != NULL)
1429 free (free_opt);
1430 return (err);
1431
1432write_error:
1433 ierrno = errno;
1434 if (fclose (fprcs) < 0)
1435 error (0, errno, "cannot close %s", rcs);
1436write_error_noclose:
1437 if (fclose (fpuser) < 0)
1438 error (0, errno, "cannot close %s", user);
1439 if (add_logfp != NULL)
1440 fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
1441 error (0, ierrno, "ERROR: cannot write file %s", rcs);
1442 if (ierrno == ENOSPC)
1443 {
1444 if (CVS_UNLINK (rcs) < 0)
1445 error (0, errno, "cannot remove %s", rcs);
1446 if (add_logfp != NULL)
1447 fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
1448 error (1, 0, "ERROR: out of space - aborting");
1449 }
1450read_error:
1451 if (tocvsPath)
1452 if (unlink_file_dir (tocvsPath) < 0)
1453 error (0, errno, "cannot remove %s", tocvsPath);
1454
1455 if (free_opt != NULL)
1456 free (free_opt);
1457
1458 return (err + 1);
1459}
1460
1461/*
1462 * Write SIZE bytes at BUF to FP, expanding @ signs into double @
1463 * signs. If an error occurs, return a negative value and set errno
1464 * to indicate the error. If not, return a nonnegative value.
1465 */
1466int
1467expand_at_signs (buf, size, fp)
1468 char *buf;
1469 off_t size;
1470 FILE *fp;
1471{
1472 register char *cp, *next;
1473
1474 cp = buf;
1475 while ((next = memchr (cp, '@', size)) != NULL)
1476 {
1477 int len;
1478
1479 ++next;
1480 len = next - cp;
1481 if (fwrite (cp, 1, len, fp) != len)
1482 return EOF;
1483 if (putc ('@', fp) == EOF)
1484 return EOF;
1485 cp = next;
1486 size -= len;
1487 }
1488
1489 if (fwrite (cp, 1, size, fp) != size)
1490 return EOF;
1491
1492 return 1;
1493}
1494
1495/*
1496 * Write an update message to (potentially) the screen and the log file.
1497 */
1498static void
1499add_log (ch, fname)
1500 int ch;
1501 char *fname;
1502{
1503 if (!really_quiet) /* write to terminal */
1504 {
1505 char buf[2];
1506 buf[0] = ch;
1507 buf[1] = ' ';
1508 cvs_output (buf, 2);
1509 if (repos_len)
1510 {
1511 cvs_output (repository + repos_len + 1, 0);
1512 cvs_output ("/", 1);
1513 }
1514 else if (repository[0] != '\0')
1515 {
1516 cvs_output (repository, 0);
1517 cvs_output ("/", 1);
1518 }
1519 cvs_output (fname, 0);
1520 cvs_output ("\n", 1);
1521 }
1522
1523 if (repos_len) /* write to logfile */
1524 (void) fprintf (logfp, "%c %s/%s\n", ch,
1525 repository + repos_len + 1, fname);
1526 else if (repository[0])
1527 (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
1528 else
1529 (void) fprintf (logfp, "%c %s\n", ch, fname);
1530}
1531
1532/*
1533 * This is the recursive function that walks the argument directory looking
1534 * for sub-directories that have CVS administration files in them and updates
1535 * them recursively.
1536 *
1537 * Note that we do not follow symbolic links here, which is a feature!
1538 */
1539static int
1540import_descend_dir (message, dir, vtag, targc, targv)
1541 char *message;
1542 char *dir;
1543 char *vtag;
1544 int targc;
1545 char *targv[];
1546{
1547 struct saved_cwd cwd;
1548 char *cp;
1549 int ierrno, err;
1550 char *rcs = NULL;
1551
1552 if (islink (dir))
1553 return (0);
1554 if (save_cwd (&cwd))
1555 {
1556 fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
1557 return (1);
1558 }
1559
1560 /* Concatenate DIR to the end of REPOSITORY. */
1561 if (repository[0] == '\0')
1562 {
1563 char *new = xstrdup (dir);
1564 free (repository);
1565 repository = new;
1566 }
1567 else
1568 {
1569 char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
1570 strcpy (new, repository);
1571 (void) strcat (new, "/");
1572 (void) strcat (new, dir);
1573 free (repository);
1574 repository = new;
1575 }
1576
1577#ifdef CLIENT_SUPPORT
1578 if (!quiet && !current_parsed_root->isremote)
1579#else
1580 if (!quiet)
1581#endif
1582 error (0, 0, "Importing %s", repository);
1583
1584 if ( CVS_CHDIR (dir) < 0)
1585 {
1586 ierrno = errno;
1587 fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
1588 error (0, ierrno, "ERROR: cannot chdir to %s", repository);
1589 err = 1;
1590 goto out;
1591 }
1592#ifdef CLIENT_SUPPORT
1593 if (!current_parsed_root->isremote && !isdir (repository))
1594#else
1595 if (!isdir (repository))
1596#endif
1597 {
1598 rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
1599 (void) sprintf (rcs, "%s%s", repository, RCSEXT);
1600 if (isfile (repository) || isfile(rcs))
1601 {
1602 fperrmsg (logfp, 0, 0,
1603 "ERROR: %s is a file, should be a directory!",
1604 repository);
1605 error (0, 0, "ERROR: %s is a file, should be a directory!",
1606 repository);
1607 err = 1;
1608 goto out;
1609 }
1610 if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
1611 {
1612 ierrno = errno;
1613 fperrmsg (logfp, 0, ierrno,
1614 "ERROR: cannot mkdir %s -- not added", repository);
1615 error (0, ierrno,
1616 "ERROR: cannot mkdir %s -- not added", repository);
1617 err = 1;
1618 goto out;
1619 }
1620 }
1621 err = import_descend (message, vtag, targc, targv);
1622 out:
1623 if (rcs != NULL)
1624 free (rcs);
1625 if ((cp = strrchr (repository, '/')) != NULL)
1626 *cp = '\0';
1627 else
1628 repository[0] = '\0';
1629 if (restore_cwd (&cwd, NULL))
1630 error_exit ();
1631 free_cwd (&cwd);
1632 return (err);
1633}