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