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