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