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