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