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