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