xref: /openbsd-src/gnu/usr.bin/cvs/src/import.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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 (CVSroot_directory == 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 (CVSroot_directory) + strlen (argv[0])
181 			      + 10);
182 	(void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
183 	repos_len = strlen (CVSroot_directory);
184     }
185     else
186     {
187 	/* It is somewhere between a security hole and "unexpected" to
188 	   let the client start mucking around outside the cvsroot
189 	   (wouldn't get the right CVSROOT configuration, &c).  */
190 	error (1, 0, "directory %s not relative within the repository",
191 	       argv[0]);
192     }
193 
194     /*
195      * Consistency checks on the specified vendor branch.  It must be
196      * composed of only numbers and dots ('.').  Also, for now we only
197      * support branching to a single level, so the specified vendor branch
198      * must only have two dots in it (like "1.1.1").
199      */
200     for (cp = vbranch; *cp != '\0'; cp++)
201 	if (!isdigit ((unsigned char) *cp) && *cp != '.')
202 	    error (1, 0, "%s is not a numeric branch", vbranch);
203     if (numdots (vbranch) != 2)
204 	error (1, 0, "Only branches with two dots are supported: %s", vbranch);
205     vhead = xstrdup (vbranch);
206     cp = strrchr (vhead, '.');
207     *cp = '\0';
208 
209 #ifdef CLIENT_SUPPORT
210     if (client_active)
211     {
212 	/* For rationale behind calling start_server before do_editor, see
213 	   commit.c  */
214 	start_server ();
215     }
216 #endif
217 
218     if (use_editor)
219     {
220 	do_editor ((char *) NULL, &message, repository,
221 		   (List *) NULL);
222     }
223     do_verify (message, repository);
224     msglen = message == NULL ? 0 : strlen (message);
225     if (msglen == 0 || message[msglen - 1] != '\n')
226     {
227 	char *nm = xmalloc (msglen + 2);
228 	*nm = '\0';
229 	if (message != NULL)
230 	{
231 	    (void) strcpy (nm, message);
232 	    free (message);
233 	}
234 	(void) strcat (nm + msglen, "\n");
235 	message = nm;
236     }
237 
238 #ifdef CLIENT_SUPPORT
239     if (client_active)
240     {
241 	int err;
242 
243 	if (vbranch[0] != '\0')
244 	    option_with_arg ("-b", vbranch);
245 	if (message)
246 	    option_with_arg ("-m", message);
247 	if (keyword_opt != NULL)
248 	    option_with_arg ("-k", keyword_opt);
249 	/* The only ignore processing which takes place on the server side
250 	   is the CVSROOT/cvsignore file.  But if the user specified -I !,
251 	   the documented behavior is to not process said file.  */
252 	if (ign_inhibit_server)
253 	{
254 	    send_arg ("-I");
255 	    send_arg ("!");
256 	}
257 	wrap_send ();
258 
259 	{
260 	    int i;
261 	    for (i = 0; i < argc; ++i)
262 		send_arg (argv[i]);
263 	}
264 
265 	logfp = stdin;
266 	client_import_setup (repository);
267 	err = import_descend (message, argv[1], argc - 2, argv + 2);
268 	client_import_done ();
269 	if (message)
270 	    free (message);
271 	free (repository);
272 	free (vbranch);
273 	free (vhead);
274 	send_to_server ("import\012", 0);
275 	err += get_responses_and_close ();
276 	return err;
277     }
278 #endif
279 
280     if (!safe_location ())
281     {
282 	error (1, 0, "attempt to import the repository");
283     }
284 
285     /*
286      * Make all newly created directories writable.  Should really use a more
287      * sophisticated security mechanism here.
288      */
289     (void) umask (cvsumask);
290     make_directories (repository);
291 
292     /* Create the logfile that will be logged upon completion */
293     tmpfile = cvs_temp_name ();
294     if ((logfp = CVS_FOPEN (tmpfile, "w+")) == 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 = 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 (client_active)
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) 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 __mc68000__
903     {"s", "| "},			/* assembler	 */
904 #endif
905 #ifdef __pdp11__
906     {"s", "/ "},			/* assembler	 */
907 #endif
908 #ifdef __vax__
909     {"s", "# "},			/* assembler	 */
910 #endif
911 #ifdef __ksr__
912     {"s", "# "},			/* assembler	 */
913     {"S", "# "},			/* Macro assembler */
914 #endif
915     {"sh", "# "},			/* shell	 */
916     {"sl", "% "},			/* psl		 */
917     {"spec", "-- "},			/* Ada		 */
918     {"tex", "% "},			/* tex		 */
919     {"y", " * "},			/* yacc		 */
920     {"ye", " * "},			/* yacc-efl	 */
921     {"yr", " * "},			/* yacc-ratfor	 */
922     {"", "# "},				/* default for empty suffix	 */
923     {NULL, "# "}			/* default for unknown suffix;	 */
924 /* must always be last		 */
925 };
926 
927 static char *
928 get_comment (user)
929     char *user;
930 {
931     char *cp, *suffix;
932     char *suffix_path;
933     int i;
934     char *retval;
935 
936     suffix_path = xmalloc (strlen (user) + 5);
937     cp = strrchr (user, '.');
938     if (cp != NULL)
939     {
940 	cp++;
941 
942 	/*
943 	 * Convert to lower-case, since we are not concerned about the
944 	 * case-ness of the suffix.
945 	 */
946 	(void) strcpy (suffix_path, cp);
947 	for (cp = suffix_path; *cp; cp++)
948 	    if (isupper ((unsigned char) *cp))
949 		*cp = tolower (*cp);
950 	suffix = suffix_path;
951     }
952     else
953 	suffix = "";			/* will use the default */
954     for (i = 0;; i++)
955     {
956 	if (comtable[i].suffix == NULL)
957 	{
958 	    /* Default.  Note we'll always hit this case before we
959 	       ever return NULL.  */
960 	    retval = comtable[i].comlead;
961 	    break;
962 	}
963 	if (strcmp (suffix, comtable[i].suffix) == 0)
964 	{
965 	    retval = comtable[i].comlead;
966 	    break;
967 	}
968     }
969     free (suffix_path);
970     return retval;
971 }
972 
973 /* Create a new RCS file from scratch.
974 
975    This probably should be moved to rcs.c now that it is called from
976    places outside import.c.
977 
978    Return value is 0 for success, or nonzero for failure (in which
979    case an error message will have already been printed).  */
980 int
981 add_rcs_file (message, rcs, user, add_vhead, key_opt,
982 	      add_vbranch, vtag, targc, targv,
983 	      desctext, desclen, add_logfp)
984     /* Log message for the addition.  Not used if add_vhead == NULL.  */
985     char *message;
986     /* Filename of the RCS file to create.  */
987     char *rcs;
988     /* Filename of the file to serve as the contents of the initial
989        revision.  Even if add_vhead is NULL, we use this to determine
990        the modes to give the new RCS file.  */
991     char *user;
992 
993     /* Revision number of head that we are adding.  Normally 1.1 but
994        could be another revision as long as ADD_VBRANCH is a branch
995        from it.  If NULL, then just add an empty file without any
996        revisions (similar to the one created by "rcs -i").  */
997     char *add_vhead;
998 
999     /* Keyword expansion mode, e.g., "b" for binary.  NULL means the
1000        default behavior.  */
1001     char *key_opt;
1002 
1003     /* Vendor branch to import to, or NULL if none.  If non-NULL, then
1004        vtag should also be non-NULL.  */
1005     char *add_vbranch;
1006     char *vtag;
1007     int targc;
1008     char *targv[];
1009 
1010     /* If non-NULL, description for the file.  If NULL, the description
1011        will be empty.  */
1012     char *desctext;
1013     size_t desclen;
1014 
1015     /* Write errors to here as well as via error (), or NULL if we should
1016        use only error ().  */
1017     FILE *add_logfp;
1018 {
1019     FILE *fprcs, *fpuser;
1020     struct stat sb;
1021     struct tm *ftm;
1022     time_t now;
1023     char altdate1[MAXDATELEN];
1024     char *author;
1025     int i, ierrno, err = 0;
1026     mode_t mode;
1027     char *tocvsPath;
1028     char *userfile;
1029     char *local_opt = key_opt;
1030     char *free_opt = NULL;
1031     mode_t file_type;
1032 
1033     if (noexec)
1034 	return (0);
1035 
1036     /* Note that as the code stands now, the -k option overrides any
1037        settings in wrappers (whether CVSROOT/cvswrappers, -W, or
1038        whatever).  Some have suggested this should be the other way
1039        around.  As far as I know the documentation doesn't say one way
1040        or the other.  Before making a change of this sort, should think
1041        about what is best, document it (in cvs.texinfo and NEWS), &c.  */
1042 
1043     if (local_opt == NULL)
1044     {
1045 	if (wrap_name_has (user, WRAP_RCSOPTION))
1046 	{
1047 	    local_opt = free_opt = wrap_rcsoption (user, 0);
1048 	}
1049     }
1050 
1051     tocvsPath = wrap_tocvs_process_file (user);
1052     userfile = (tocvsPath == NULL ? user : tocvsPath);
1053 
1054     /* Opening in text mode is probably never the right thing for the
1055        server (because the protocol encodes text files in a fashion
1056        which does not depend on what the client or server OS is, as
1057        documented in cvsclient.texi), but as long as the server just
1058        runs on unix it is a moot point.  */
1059 
1060     /* If PreservePermissions is set, then make sure that the file
1061        is a plain file before trying to open it.  Longstanding (although
1062        often unpopular) CVS behavior has been to follow symlinks, so we
1063        maintain that behavior if PreservePermissions is not on.
1064 
1065        NOTE: this error message used to be `cannot fstat', but is now
1066        `cannot lstat'.  I don't see a way around this, since we must
1067        stat the file before opening it. -twp */
1068 
1069     if (CVS_LSTAT (userfile, &sb) < 0)
1070     {
1071 	/* not fatal, continue import */
1072 	if (add_logfp != NULL)
1073 	    fperrmsg (add_logfp, 0, errno,
1074 			  "ERROR: cannot lstat file %s", userfile);
1075 	error (0, errno, "cannot lstat file %s", userfile);
1076 	goto read_error;
1077     }
1078     file_type = sb.st_mode & S_IFMT;
1079 
1080     fpuser = NULL;
1081     if (!preserve_perms || file_type == S_IFREG)
1082     {
1083 	fpuser = CVS_FOPEN (userfile,
1084 			    ((local_opt != NULL && strcmp (local_opt, "b") == 0)
1085 			     ? "rb"
1086 			     : "r")
1087 	    );
1088 	if (fpuser == NULL)
1089 	{
1090 	    /* not fatal, continue import */
1091 	    if (add_logfp != NULL)
1092 		fperrmsg (add_logfp, 0, errno,
1093 			  "ERROR: cannot read file %s", userfile);
1094 	    error (0, errno, "ERROR: cannot read file %s", userfile);
1095 	    goto read_error;
1096 	}
1097     }
1098 
1099     fprcs = CVS_FOPEN (rcs, "w+b");
1100     if (fprcs == NULL)
1101     {
1102 	ierrno = errno;
1103 	goto write_error_noclose;
1104     }
1105 
1106     /*
1107      * putadmin()
1108      */
1109     if (add_vhead != NULL)
1110     {
1111 	if (fprintf (fprcs, "head     %s;\012", add_vhead) < 0)
1112 	    goto write_error;
1113     }
1114     else
1115     {
1116 	if (fprintf (fprcs, "head     ;\012") < 0)
1117 	    goto write_error;
1118     }
1119 
1120     if (add_vbranch != NULL)
1121     {
1122 	if (fprintf (fprcs, "branch   %s;\012", add_vbranch) < 0)
1123 	    goto write_error;
1124     }
1125     if (fprintf (fprcs, "access   ;\012") < 0 ||
1126 	fprintf (fprcs, "symbols  ") < 0)
1127     {
1128 	goto write_error;
1129     }
1130 
1131     for (i = targc - 1; i >= 0; i--)
1132     {
1133 	/* RCS writes the symbols backwards */
1134 	assert (add_vbranch != NULL);
1135 	if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
1136 	    goto write_error;
1137     }
1138 
1139     if (add_vbranch != NULL)
1140     {
1141 	if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
1142 	    goto write_error;
1143     }
1144     if (fprintf (fprcs, ";\012") < 0)
1145 	goto write_error;
1146 
1147     if (fprintf (fprcs, "locks    ; strict;\012") < 0 ||
1148 	/* XXX - make sure @@ processing works in the RCS file */
1149 	fprintf (fprcs, "comment  @%s@;\012", get_comment (user)) < 0)
1150     {
1151 	goto write_error;
1152     }
1153 
1154     if (local_opt != NULL)
1155     {
1156 	if (fprintf (fprcs, "expand   @%s@;\012", local_opt) < 0)
1157 	{
1158 	    goto write_error;
1159 	}
1160     }
1161 
1162     if (fprintf (fprcs, "\012") < 0)
1163       goto write_error;
1164 
1165     /* Write the revision(s), with the date and author and so on
1166        (that is "delta" rather than "deltatext" from rcsfile(5)).  */
1167     if (add_vhead != NULL)
1168     {
1169 	if (use_file_modtime)
1170 	    now = sb.st_mtime;
1171 	else
1172 	    (void) time (&now);
1173 	ftm = gmtime (&now);
1174 	(void) sprintf (altdate1, DATEFORM,
1175 			ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1176 			ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1177 			ftm->tm_min, ftm->tm_sec);
1178 	author = getcaller ();
1179 
1180 	if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1181 	fprintf (fprcs, "date     %s;  author %s;  state Exp;\012",
1182 		 altdate1, author) < 0)
1183 	goto write_error;
1184 
1185 	if (fprintf (fprcs, "branches") < 0)
1186 	    goto write_error;
1187 	if (add_vbranch != NULL)
1188 	{
1189 	    if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
1190 		goto write_error;
1191 	}
1192 	if (fprintf (fprcs, ";\012") < 0)
1193 	    goto write_error;
1194 
1195 	if (fprintf (fprcs, "next     ;\012") < 0)
1196 	    goto write_error;
1197 
1198 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1199 	/* Store initial permissions if necessary. */
1200 	if (preserve_perms)
1201 	{
1202 	    if (file_type == S_IFLNK)
1203 	    {
1204 		char *link = xreadlink (userfile);
1205 		if (fprintf (fprcs, "symlink\t@") < 0 ||
1206 		    expand_at_signs (link, strlen (link), fprcs) < 0 ||
1207 		    fprintf (fprcs, "@;\012") < 0)
1208 		    goto write_error;
1209 		free (link);
1210 	    }
1211 	    else
1212 	    {
1213 		if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
1214 		    goto write_error;
1215 		if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
1216 		    goto write_error;
1217 		if (fprintf (fprcs, "permissions\t%o;\012",
1218 			     sb.st_mode & 07777) < 0)
1219 		    goto write_error;
1220 		switch (file_type)
1221 		{
1222 		    case S_IFREG: break;
1223 		    case S_IFCHR:
1224 		    case S_IFBLK:
1225 #ifdef HAVE_ST_RDEV
1226 			if (fprintf (fprcs, "special\t%s %lu;\012",
1227 				     (file_type == S_IFCHR
1228 				      ? "character"
1229 				      : "block"),
1230 				     (unsigned long) sb.st_rdev) < 0)
1231 			    goto write_error;
1232 #else
1233 			error (0, 0,
1234 "can't import %s: unable to import device files on this system",
1235 userfile);
1236 #endif
1237 			break;
1238 		    default:
1239 			error (0, 0,
1240 			       "can't import %s: unknown kind of special file",
1241 			       userfile);
1242 		}
1243 	    }
1244 	}
1245 #endif
1246 
1247 	if (add_vbranch != NULL)
1248 	{
1249 	    if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1250 		fprintf (fprcs, "date     %s;  author %s;  state Exp;\012",
1251 			 altdate1, author) < 0 ||
1252 		fprintf (fprcs, "branches ;\012") < 0 ||
1253 		fprintf (fprcs, "next     ;\012") < 0)
1254 		goto write_error;
1255 
1256 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1257 	    /* Store initial permissions if necessary. */
1258 	    if (preserve_perms)
1259 	    {
1260 		if (file_type == S_IFLNK)
1261 		{
1262 		    char *link = xreadlink (userfile);
1263 		    if (fprintf (fprcs, "symlink\t@") < 0 ||
1264 			expand_at_signs (link, strlen (link), fprcs) < 0 ||
1265 			fprintf (fprcs, "@;\012") < 0)
1266 			goto write_error;
1267 		    free (link);
1268 		}
1269 		else
1270 		{
1271 		    if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
1272 			fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
1273 			fprintf (fprcs, "permissions\t%o;\012",
1274 				 sb.st_mode & 07777) < 0)
1275 			goto write_error;
1276 
1277 		    switch (file_type)
1278 		    {
1279 			case S_IFREG: break;
1280 			case S_IFCHR:
1281 			case S_IFBLK:
1282 #ifdef HAVE_ST_RDEV
1283 			    if (fprintf (fprcs, "special\t%s %lu;\012",
1284 					 (file_type == S_IFCHR
1285 					  ? "character"
1286 					  : "block"),
1287 					 (unsigned long) sb.st_rdev) < 0)
1288 				goto write_error;
1289 #else
1290 			    error (0, 0,
1291 "can't import %s: unable to import device files on this system",
1292 userfile);
1293 #endif
1294 			    break;
1295 			default:
1296 			    error (0, 0,
1297 			      "cannot import %s: special file of unknown type",
1298 			       userfile);
1299 		    }
1300 		}
1301 	    }
1302 #endif
1303 
1304 	    if (fprintf (fprcs, "\012") < 0)
1305 		goto write_error;
1306 	}
1307     }
1308 
1309     /* Now write the description (possibly empty).  */
1310     if (fprintf (fprcs, "\012desc\012") < 0 ||
1311 	fprintf (fprcs, "@") < 0)
1312 	goto write_error;
1313     if (desctext != NULL)
1314     {
1315 	/* The use of off_t not size_t for the second argument is very
1316 	   strange, since we are dealing with something which definitely
1317 	   fits in memory.  */
1318 	if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
1319 	    goto write_error;
1320     }
1321     if (fprintf (fprcs, "@\012\012\012") < 0)
1322 	goto write_error;
1323 
1324     /* Now write the log messages and contents for the revision(s) (that
1325        is, "deltatext" rather than "delta" from rcsfile(5)).  */
1326     if (add_vhead != NULL)
1327     {
1328 	if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1329 	    fprintf (fprcs, "log\012@") < 0)
1330 	    goto write_error;
1331 	if (add_vbranch != NULL)
1332 	{
1333 	    /* We are going to put the log message in the revision on the
1334 	       branch.  So putting it here too seems kind of redundant, I
1335 	       guess (and that is what CVS has always done, anyway).  */
1336 	    if (fprintf (fprcs, "Initial revision\012") < 0)
1337 		goto write_error;
1338 	}
1339 	else
1340 	{
1341 	    if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
1342 		goto write_error;
1343 	}
1344 	if (fprintf (fprcs, "@\012") < 0 ||
1345 	    fprintf (fprcs, "text\012@") < 0)
1346 	{
1347 	    goto write_error;
1348 	}
1349 
1350 	/* Now copy over the contents of the file, expanding at signs.
1351 	   If preserve_perms is set, do this only for regular files. */
1352 	if (!preserve_perms || file_type == S_IFREG)
1353 	{
1354 	    char buf[8192];
1355 	    unsigned int len;
1356 
1357 	    while (1)
1358 	    {
1359 		len = fread (buf, 1, sizeof buf, fpuser);
1360 		if (len == 0)
1361 		{
1362 		    if (ferror (fpuser))
1363 			error (1, errno, "cannot read file %s for copying",
1364 			       user);
1365 		    break;
1366 		}
1367 		if (expand_at_signs (buf, len, fprcs) < 0)
1368 		    goto write_error;
1369 	    }
1370 	}
1371 	if (fprintf (fprcs, "@\012\012") < 0)
1372 	    goto write_error;
1373 	if (add_vbranch != NULL)
1374 	{
1375 	    if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1376 		fprintf (fprcs, "log\012@") < 0 ||
1377 		expand_at_signs (message,
1378 				 (off_t) strlen (message), fprcs) < 0 ||
1379 		fprintf (fprcs, "@\012text\012") < 0 ||
1380 		fprintf (fprcs, "@@\012") < 0)
1381 		goto write_error;
1382 	}
1383     }
1384 
1385     if (fclose (fprcs) == EOF)
1386     {
1387 	ierrno = errno;
1388 	goto write_error_noclose;
1389     }
1390     /* Close fpuser only if we opened it to begin with. */
1391     if (fpuser != NULL)
1392     {
1393 	if (fclose (fpuser) < 0)
1394 	    error (0, errno, "cannot close %s", user);
1395     }
1396 
1397     /*
1398      * Fix the modes on the RCS files.  The user modes of the original
1399      * user file are propagated to the group and other modes as allowed
1400      * by the repository umask, except that all write permissions are
1401      * turned off.
1402      */
1403     mode = (sb.st_mode |
1404 	    (sb.st_mode & S_IRWXU) >> 3 |
1405 	    (sb.st_mode & S_IRWXU) >> 6) &
1406 	   ~cvsumask &
1407 	   ~(S_IWRITE | S_IWGRP | S_IWOTH);
1408     if (chmod (rcs, mode) < 0)
1409     {
1410 	ierrno = errno;
1411 	if (add_logfp != NULL)
1412 	    fperrmsg (add_logfp, 0, ierrno,
1413 		      "WARNING: cannot change mode of file %s", rcs);
1414 	error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
1415 	err++;
1416     }
1417     if (tocvsPath)
1418 	if (unlink_file_dir (tocvsPath) < 0)
1419 		error (0, errno, "cannot remove %s", tocvsPath);
1420     if (free_opt != NULL)
1421 	free (free_opt);
1422     return (err);
1423 
1424 write_error:
1425     ierrno = errno;
1426     if (fclose (fprcs) < 0)
1427 	error (0, errno, "cannot close %s", rcs);
1428 write_error_noclose:
1429     if (fclose (fpuser) < 0)
1430 	error (0, errno, "cannot close %s", user);
1431     if (add_logfp != NULL)
1432 	fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
1433     error (0, ierrno, "ERROR: cannot write file %s", rcs);
1434     if (ierrno == ENOSPC)
1435     {
1436 	if (CVS_UNLINK (rcs) < 0)
1437 	    error (0, errno, "cannot remove %s", rcs);
1438 	if (add_logfp != NULL)
1439 	    fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
1440 	error (1, 0, "ERROR: out of space - aborting");
1441     }
1442 read_error:
1443     if (tocvsPath)
1444 	if (unlink_file_dir (tocvsPath) < 0)
1445 	    error (0, errno, "cannot remove %s", tocvsPath);
1446 
1447     if (free_opt != NULL)
1448 	free (free_opt);
1449 
1450     return (err + 1);
1451 }
1452 
1453 /*
1454  * Write SIZE bytes at BUF to FP, expanding @ signs into double @
1455  * signs.  If an error occurs, return a negative value and set errno
1456  * to indicate the error.  If not, return a nonnegative value.
1457  */
1458 int
1459 expand_at_signs (buf, size, fp)
1460     char *buf;
1461     off_t size;
1462     FILE *fp;
1463 {
1464     register char *cp, *next;
1465 
1466     cp = buf;
1467     while ((next = memchr (cp, '@', size)) != NULL)
1468     {
1469 	int len;
1470 
1471 	++next;
1472 	len = next - cp;
1473 	if (fwrite (cp, 1, len, fp) != len)
1474 	    return EOF;
1475 	if (putc ('@', fp) == EOF)
1476 	    return EOF;
1477 	cp = next;
1478 	size -= len;
1479     }
1480 
1481     if (fwrite (cp, 1, size, fp) != size)
1482 	return EOF;
1483 
1484     return 1;
1485 }
1486 
1487 /*
1488  * Write an update message to (potentially) the screen and the log file.
1489  */
1490 static void
1491 add_log (ch, fname)
1492     int ch;
1493     char *fname;
1494 {
1495     if (!really_quiet)			/* write to terminal */
1496     {
1497 	char buf[2];
1498 	buf[0] = ch;
1499 	buf[1] = ' ';
1500 	cvs_output (buf, 2);
1501 	if (repos_len)
1502 	{
1503 	    cvs_output (repository + repos_len + 1, 0);
1504 	    cvs_output ("/", 1);
1505 	}
1506 	else if (repository[0] != '\0')
1507 	{
1508 	    cvs_output (repository, 0);
1509 	    cvs_output ("/", 1);
1510 	}
1511 	cvs_output (fname, 0);
1512 	cvs_output ("\n", 1);
1513     }
1514 
1515     if (repos_len)			/* write to logfile */
1516 	(void) fprintf (logfp, "%c %s/%s\n", ch,
1517 			repository + repos_len + 1, fname);
1518     else if (repository[0])
1519 	(void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
1520     else
1521 	(void) fprintf (logfp, "%c %s\n", ch, fname);
1522 }
1523 
1524 /*
1525  * This is the recursive function that walks the argument directory looking
1526  * for sub-directories that have CVS administration files in them and updates
1527  * them recursively.
1528  *
1529  * Note that we do not follow symbolic links here, which is a feature!
1530  */
1531 static int
1532 import_descend_dir (message, dir, vtag, targc, targv)
1533     char *message;
1534     char *dir;
1535     char *vtag;
1536     int targc;
1537     char *targv[];
1538 {
1539     struct saved_cwd cwd;
1540     char *cp;
1541     int ierrno, err;
1542     char *rcs = NULL;
1543 
1544     if (islink (dir))
1545 	return (0);
1546     if (save_cwd (&cwd))
1547     {
1548 	fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
1549 	return (1);
1550     }
1551 
1552     /* Concatenate DIR to the end of REPOSITORY.  */
1553     if (repository[0] == '\0')
1554     {
1555 	char *new = xstrdup (dir);
1556 	free (repository);
1557 	repository = new;
1558     }
1559     else
1560     {
1561 	char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
1562 	strcpy (new, repository);
1563 	(void) strcat (new, "/");
1564 	(void) strcat (new, dir);
1565 	free (repository);
1566 	repository = new;
1567     }
1568 
1569 #ifdef CLIENT_SUPPORT
1570     if (!quiet && !client_active)
1571 #else
1572     if (!quiet)
1573 #endif
1574 	error (0, 0, "Importing %s", repository);
1575 
1576     if ( CVS_CHDIR (dir) < 0)
1577     {
1578 	ierrno = errno;
1579 	fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
1580 	error (0, ierrno, "ERROR: cannot chdir to %s", repository);
1581 	err = 1;
1582 	goto out;
1583     }
1584 #ifdef CLIENT_SUPPORT
1585     if (!client_active && !isdir (repository))
1586 #else
1587     if (!isdir (repository))
1588 #endif
1589     {
1590 	rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
1591 	(void) sprintf (rcs, "%s%s", repository, RCSEXT);
1592 	if (isfile (repository) || isfile(rcs))
1593 	{
1594 	    fperrmsg (logfp, 0, 0,
1595 		      "ERROR: %s is a file, should be a directory!",
1596 		      repository);
1597 	    error (0, 0, "ERROR: %s is a file, should be a directory!",
1598 		   repository);
1599 	    err = 1;
1600 	    goto out;
1601 	}
1602 	if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
1603 	{
1604 	    ierrno = errno;
1605 	    fperrmsg (logfp, 0, ierrno,
1606 		      "ERROR: cannot mkdir %s -- not added", repository);
1607 	    error (0, ierrno,
1608 		   "ERROR: cannot mkdir %s -- not added", repository);
1609 	    err = 1;
1610 	    goto out;
1611 	}
1612     }
1613     err = import_descend (message, vtag, targc, targv);
1614   out:
1615     if (rcs != NULL)
1616 	free (rcs);
1617     if ((cp = strrchr (repository, '/')) != NULL)
1618 	*cp = '\0';
1619     else
1620 	repository[0] = '\0';
1621     if (restore_cwd (&cwd, NULL))
1622 	error_exit ();
1623     free_cwd (&cwd);
1624     return (err);
1625 }
1626