2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
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.
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.
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
21 * Additional arguments specify more Vendor Release Tags.
28 static char *get_comment PROTO((const char *user));
29 static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
31 static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
33 static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]));
34 static int import_descend_dir PROTO((char *message, char *dir, char *vtag,
35 int targc, char *targv[]));
36 static int process_import_file PROTO((char *message, char *vfile, char *vtag,
37 int targc, char *targv[]));
38 static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc,
39 char *targv[], int inattic));
40 static void add_log PROTO((int ch, char *fname));
46 static char *repository;
48 static int use_file_modtime;
49 static char *keyword_opt = NULL;
51 static const char *const import_usage[] =
53 "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n",
54 " [-W spec] repository vendor-tag release-tags...\n",
55 "\t-d\tUse the file's modification time as the time of import.\n",
56 "\t-k sub\tSet default RCS keyword substitution mode.\n",
57 "\t-I ign\tMore files to ignore (! to reset).\n",
58 "\t-b bra\tVendor branch id.\n",
59 "\t-m msg\tLog message.\n",
60 "\t-W spec\tWrappers specification line.\n",
61 "(Specify the --help global option for a list of other help options)\n",
73 int i, c, msglen, err;
76 struct logfile_info *li;
84 vbranch = xstrdup (CVSBRANCH);
86 while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1)
92 /* The CVS 1.5 client sends these options (in addition to
93 Global_option requests), so we must ignore them. */
96 "-q or -Q must be specified before \"%s\"",
102 /* CVS 1.10 and older clients will send this, but it
103 doesn't do any good. So tell the user we can't
104 cope, rather than silently losing. */
106 "warning: not setting the time of import from the file");
107 error (0, 0, "due to client limitations");
109 use_file_modtime = 1;
113 vbranch = xstrdup (optarg);
116 #ifdef FORCE_USE_EDITOR
121 if (message) free (message);
122 message = xstrdup(optarg);
128 /* RCS_check_kflag returns strings of the form -kxx. We
129 only use it for validation, so we can free the value
130 as soon as it is returned. */
131 free (RCS_check_kflag (optarg));
132 keyword_opt = optarg;
135 wrap_add (optarg, 0);
139 usage (import_usage);
146 usage (import_usage);
148 /* This is for handling the Checkin-time request. It might seem a
149 bit odd to enable the use_file_modtime code even in the case
150 where Checkin-time was not sent for a particular file. The
151 effect is that we use the time of upload, rather than the time
152 when we call RCS_checkin. Since those times are both during
153 CVS's run, that seems OK, and it is easier to implement than
154 putting the "was Checkin-time sent" flag in CVS/Entries or some
158 use_file_modtime = 1;
160 /* Don't allow "CVS" as any directory in module path.
162 * Could abstract this to valid_module_path, but I don't think we'll need
163 * to call it from anywhere else.
165 /* for each "CVS" in path... */
167 while ((cp = strstr(cp, "CVS")) != NULL)
169 if ( /* /^CVS/ OR m#/CVS#... */
170 (cp == argv[0] || ISDIRSEP(*(cp-1)))
171 /* ...AND /CVS$/ OR m#CVS/# */
172 && (*(cp+3) == '\0' || ISDIRSEP(*(cp+3)))
176 "The word `CVS' is reserved by CVS and may not be used");
177 error (1, 0, "as a directory in a path or as a file name.");
182 for (i = 1; i < argc; i++) /* check the tags for validity */
186 RCS_check_tag (argv[i]);
187 for (j = 1; j < i; j++)
188 if (strcmp (argv[j], argv[i]) == 0)
189 error (1, 0, "tag `%s' was specified more than once", argv[i]);
192 /* XXX - this should be a module, not just a pathname */
193 if (!isabsolute (argv[0]) && pathname_levels (argv[0]) == 0)
195 if (current_parsed_root == NULL)
197 error (0, 0, "missing CVSROOT environment variable\n");
198 error (1, 0, "Set it or specify the '-d' option to %s.",
201 repository = xmalloc (strlen (current_parsed_root->directory)
204 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
205 repos_len = strlen (current_parsed_root->directory);
209 /* It is somewhere between a security hole and "unexpected" to
210 let the client start mucking around outside the cvsroot
211 (wouldn't get the right CVSROOT configuration, &c). */
212 error (1, 0, "directory %s not relative within the repository",
217 * Consistency checks on the specified vendor branch. It must be
218 * composed of only numbers and dots ('.'). Also, for now we only
219 * support branching to a single level, so the specified vendor branch
220 * must only have two dots in it (like "1.1.1").
224 int ret = regcomp (&pat, "^[1-9][0-9]*\\.[1-9][0-9]*\\.[1-9][0-9]*$",
227 if (regexec (&pat, vbranch, 0, NULL, 0))
230 "Only numeric branch specifications with two dots are\n"
231 "supported by import, not `%s'. For example: `1.1.1'.",
237 /* Set vhead to the branch's parent. */
238 vhead = xstrdup (vbranch);
239 cp = strrchr (vhead, '.');
242 #ifdef CLIENT_SUPPORT
243 if (current_parsed_root->isremote)
245 /* For rationale behind calling start_server before do_editor, see
251 if (!server_active && use_editor)
253 do_editor ((char *) NULL, &message,
254 current_parsed_root->isremote ? (char *) NULL : repository,
257 do_verify (&message, repository);
258 msglen = message == NULL ? 0 : strlen (message);
259 if (msglen == 0 || message[msglen - 1] != '\n')
261 char *nm = xmalloc (msglen + 2);
265 (void) strcpy (nm, message);
268 (void) strcat (nm + msglen, "\n");
272 #ifdef CLIENT_SUPPORT
273 if (current_parsed_root->isremote)
277 if (vbranch[0] != '\0')
278 option_with_arg ("-b", vbranch);
279 option_with_arg ("-m", message ? message : "");
280 if (keyword_opt != NULL)
281 option_with_arg ("-k", keyword_opt);
282 /* The only ignore processing which takes place on the server side
283 is the CVSROOT/cvsignore file. But if the user specified -I !,
284 the documented behavior is to not process said file. */
285 if (ign_inhibit_server)
294 for (i = 0; i < argc; ++i)
299 client_import_setup (repository);
300 err = import_descend (message, argv[1], argc - 2, argv + 2);
301 client_import_done ();
307 send_to_server ("import\012", 0);
308 err += get_responses_and_close ();
313 if (!safe_location ( NULL ))
315 error (1, 0, "attempt to import the repository");
319 * Make all newly created directories writable. Should really use a more
320 * sophisticated security mechanism here.
322 (void) umask (cvsumask);
323 make_directories (repository);
325 /* Create the logfile that will be logged upon completion */
326 if ((logfp = cvs_temp_file (&tmpfile)) == NULL)
327 error (1, errno, "cannot create temporary file `%s'",
328 tmpfile ? tmpfile : "(null)");
329 /* On systems where we can unlink an open file, do so, so it will go
330 away no matter how we exit. FIXME-maybe: Should be checking for
331 errors but I'm not sure which error(s) we get if we are on a system
332 where one can't unlink open files. */
333 (void) CVS_UNLINK (tmpfile);
334 (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
335 (void) fprintf (logfp, "Release Tags:\t");
336 for (i = 2; i < argc; i++)
337 (void) fprintf (logfp, "%s\n\t\t", argv[i]);
338 (void) fprintf (logfp, "\n");
341 err = import_descend (message, argv[1], argc - 2, argv + 2);
348 cvs_output_tagged ("+importmergecmd", NULL);
349 cvs_output_tagged ("newline", NULL);
350 sprintf (buf, "%d", conflicts);
351 cvs_output_tagged ("conflicts", buf);
352 cvs_output_tagged ("text", " conflicts created by this import.");
353 cvs_output_tagged ("newline", NULL);
354 cvs_output_tagged ("text",
355 "Use the following command to help the merge:");
356 cvs_output_tagged ("newline", NULL);
357 cvs_output_tagged ("newline", NULL);
358 cvs_output_tagged ("text", "\t");
359 cvs_output_tagged ("text", program_name);
360 if (CVSroot_cmdline != NULL)
362 cvs_output_tagged ("text", " -d ");
363 cvs_output_tagged ("text", CVSroot_cmdline);
365 cvs_output_tagged ("text", " checkout -j");
366 cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
367 cvs_output_tagged ("text", " -j");
368 cvs_output_tagged ("mergetag2", argv[2]);
369 cvs_output_tagged ("text", " ");
370 cvs_output_tagged ("repository", argv[0]);
371 cvs_output_tagged ("newline", NULL);
372 cvs_output_tagged ("newline", NULL);
373 cvs_output_tagged ("-importmergecmd", NULL);
376 /* FIXME: I'm not sure whether we need to put this information
377 into the loginfo. If we do, then note that it does not
378 report any required -d option. There is no particularly
379 clean way to tell the server about the -d option used by
381 (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
383 (void) fprintf (logfp,
384 "Use the following command to help the merge:\n\n");
385 (void) fprintf (logfp, "\t%s checkout ", program_name);
386 (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
387 argv[1], argv[1], argv[0]);
392 cvs_output ("\nNo conflicts created by this import\n\n", 0);
393 (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
397 * Write out the logfile and clean up.
402 p->delproc = update_delproc;
403 p->key = xstrdup ("- Imported sources");
404 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
406 li->tag = xstrdup (vbranch);
407 li->rev_old = li->rev_new = NULL;
409 (void) addnode (ulist, p);
410 Update_Logfile (repository, message, logfp, ulist);
412 if (fclose (logfp) < 0)
413 error (0, errno, "error closing %s", tmpfile);
415 /* Make sure the temporary file goes away, even on systems that don't let
416 you delete a file that's in use. */
417 if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
418 error (0, errno, "cannot remove %s", tmpfile);
430 /* Process all the files in ".", then descend into other directories.
431 Returns 0 for success, or >0 on error (in which case a message
432 will have been printed). */
434 import_descend (message, vtag, targc, targv)
443 List *dirlist = NULL;
445 /* first, load up any per-directory ignore lists */
446 ign_add_file (CVSDOTIGNORE, 1);
447 wrap_add_file (CVSDOTWRAPPER, 1);
449 if (!current_parsed_root->isremote)
450 lock_dir_for_write (repository);
452 if ((dirp = CVS_OPENDIR (".")) == NULL)
454 error (0, errno, "cannot open directory");
460 while ((dp = CVS_READDIR (dirp)) != NULL)
462 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
463 goto one_more_time_boys;
465 /* CVS directories are created in the temp directory by
466 server.c because it doesn't special-case import. So
467 don't print a message about them, regardless of -I!. */
468 if (server_active && strcmp (dp->d_name, CVSADM) == 0)
469 goto one_more_time_boys;
471 if (ign_name (dp->d_name))
473 add_log ('I', dp->d_name);
474 goto one_more_time_boys;
479 (dp->d_type == DT_DIR
480 || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
484 && !wrap_name_has (dp->d_name, WRAP_TOCVS)
493 n->key = xstrdup (dp->d_name);
499 || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
505 add_log ('L', dp->d_name);
510 #ifdef CLIENT_SUPPORT
511 if (current_parsed_root->isremote)
512 err += client_process_import_file (message, dp->d_name,
515 keyword_opt != NULL &&
516 keyword_opt[0] == 'b',
520 err += process_import_file (message, dp->d_name,
528 error (0, errno, "cannot read directory");
531 (void) CVS_CLOSEDIR (dirp);
534 if (!current_parsed_root->isremote)
541 head = dirlist->list;
542 for (p = head->next; p != head; p = p->next)
544 err += import_descend_dir (message, p->key, vtag, targc, targv);
554 * Process the argument import file.
557 process_import_file (message, vfile, vtag, targc, targv)
567 rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT)
569 (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
574 attic_name = xmalloc (strlen (repository) + strlen (vfile) +
575 sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
576 (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
578 if (!isfile (attic_name))
581 char *free_opt = NULL;
582 char *our_opt = keyword_opt;
586 * A new import source file; it doesn't exist as a ,v within the
587 * repository nor in the Attic -- create it anew.
589 add_log ('N', vfile);
591 #ifdef SERVER_SUPPORT
592 /* The most reliable information on whether the file is binary
593 is what the client told us. That is because if the client had
594 the wrong idea about binaryness, it corrupted the file, so
595 we might as well believe the client. */
601 /* Reading all the entries for each file is fairly silly, and
602 probably slow. But I am too lazy at the moment to do
604 entries = Entries_Open (0, NULL);
605 node = findnode_fn (entries, vfile);
608 Entnode *entdata = node->data;
610 if (entdata->type == ENT_FILE)
612 assert (entdata->options[0] == '-'
613 && entdata->options[1] == 'k');
614 our_opt = xstrdup (entdata->options + 2);
618 Entries_Close (entries);
622 retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
623 vbranch, vtag, targc, targv,
625 if (free_opt != NULL)
636 * an rcs file exists. have to do things the official, slow, way.
638 return (update_rcs_file (message, vfile, vtag, targc, targv, inattic));
642 * The RCS file exists; update it by adding the new import file to the
643 * (possibly already existing) vendor branch.
646 update_rcs_file (message, vfile, vtag, targc, targv, inattic)
658 struct file_info finfo;
660 memset (&finfo, 0, sizeof finfo);
662 /* Not used, so don't worry about it. */
663 finfo.update_dir = NULL;
664 finfo.fullname = finfo.file;
665 finfo.repository = repository;
666 finfo.entries = NULL;
668 vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL,
670 if (vers->vn_rcs != NULL
671 && !RCS_isdead(vers->srcfile, vers->vn_rcs))
676 * The rcs file does have a revision on the vendor branch. Compare
677 * this revision with the import file; if they match exactly, there
678 * is no need to install the new import file as a new revision to the
679 * branch. Just tag the revision with the new import tags.
681 * This is to try to cut down the number of "C" conflict messages for
682 * locally modified import source files.
684 tocvsPath = wrap_tocvs_process_file (vfile);
685 /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
687 expand = vers->srcfile->expand != NULL &&
688 vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
689 different = RCS_cmp_file( vers->srcfile, vers->vn_rcs, (char **)NULL,
690 (char *)NULL, expand, vfile );
692 if (unlink_file_dir (tocvsPath) < 0)
693 error (0, errno, "cannot remove %s", tocvsPath);
700 * The two files are identical. Just update the tags, print the
701 * "U", signifying that the file has changed, but needs no
702 * attention, and we're done.
704 if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
706 add_log ('U', vfile);
712 /* We may have failed to parse the RCS file; check just in case */
713 if (vers->srcfile == NULL ||
714 add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
715 add_tags (vers->srcfile, vfile, vtag, targc, targv))
721 if (vers->srcfile->branch == NULL || inattic ||
722 strcmp (vers->srcfile->branch, vbranch) != 0)
729 add_log (letter, vfile);
736 * Add the revision to the vendor branch
739 add_rev (message, rcs, vfile, vers)
745 int locked, status, ierrno;
754 /* Before RCS_lock existed, we were directing stdout, as well as
755 stderr, from the RCS command, to DEVNULL. I wouldn't guess that
756 was necessary, but I don't know for sure. */
757 /* Earlier versions of this function printed a `fork failed' error
758 when RCS_lock returned an error code. That's not appropriate
759 now that RCS_lock is librarified, but should the error text be
761 if (RCS_lock (rcs, vbranch, 1) != 0)
764 RCS_rewrite (rcs, NULL, NULL);
766 tocvsPath = wrap_tocvs_process_file (vfile);
768 status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
770 (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
771 | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
774 if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
775 error (0, errno, "cannot remove %s", tocvsPath);
781 fperrmsg (logfp, 0, status == -1 ? ierrno : 0,
782 "ERROR: Check-in of %s failed", rcs->path);
783 error (0, status == -1 ? ierrno : 0,
784 "ERROR: Check-in of %s failed", rcs->path);
788 (void) RCS_unlock(rcs, vbranch, 0);
789 RCS_rewrite (rcs, NULL, NULL);
797 * Add the vendor branch tag and all the specified import release tags to the
798 * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
799 * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
803 add_tags (rcs, vfile, vtag, targc, targv)
813 struct file_info finfo;
818 if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
821 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
822 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
823 error (0, retcode == -1 ? ierrno : 0,
824 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
827 RCS_rewrite (rcs, NULL, NULL);
829 memset (&finfo, 0, sizeof finfo);
831 /* Not used, so don't worry about it. */
832 finfo.update_dir = NULL;
833 finfo.fullname = finfo.file;
834 finfo.repository = repository;
835 finfo.entries = NULL;
837 vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
838 for (i = 0; i < targc; i++)
840 if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
841 RCS_rewrite (rcs, NULL, NULL);
845 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
846 "WARNING: Couldn't add tag %s to %s", targv[i],
848 error (0, retcode == -1 ? ierrno : 0,
849 "WARNING: Couldn't add tag %s to %s", targv[i],
858 * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
862 char *suffix, *comlead;
865 static const struct compair comtable[] =
869 * comtable pairs each filename suffix with a comment leader. The comment
870 * leader is placed before each line generated by the $Log keyword. This
871 * table is used to guess the proper comment leader from the working file's
872 * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
873 * languages without multiline comments; for others they are optional.
875 * I believe that the comment leader is unused if you are using RCS 5.7, which
876 * decides what leader to use based on the text surrounding the $Log keyword
877 * rather than a specified comment leader.
879 {"a", "-- "}, /* Ada */
882 {"asm", ";; "}, /* assembler (MS-DOS) */
883 {"ads", "-- "}, /* Ada */
884 {"bas", "' "}, /* Visual Basic code */
885 {"bat", ":: "}, /* batch (MS-DOS) */
886 {"body", "-- "}, /* Ada */
887 {"c", " * "}, /* C */
888 {"c++", "// "}, /* C++ in all its infinite guises */
892 {"m", "// "}, /* Objective-C */
893 {"cl", ";;; "}, /* Common Lisp */
894 {"cmd", ":: "}, /* command (OS/2) */
895 {"cmf", "c "}, /* CM Fortran */
896 {"cs", " * "}, /* C* */
897 {"csh", "# "}, /* shell */
898 {"dlg", " * "}, /* MS Windows dialog file */
899 {"e", "# "}, /* efl */
900 {"epsf", "% "}, /* encapsulated postscript */
901 {"epsi", "% "}, /* encapsulated postscript */
902 {"el", "; "}, /* Emacs Lisp */
903 {"f", "c "}, /* Fortran */
905 {"frm", "' "}, /* Visual Basic form */
906 {"h", " * "}, /* C-header */
907 {"hh", "// "}, /* C++ header */
910 {"in", "# "}, /* for Makefile.in */
911 {"l", " * "}, /* lex (conflict between lex and
913 {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
915 {"mak", "# "}, /* makefile, e.g. Visual C++ */
916 {"me", ".\\\" "}, /* me-macros t/nroff */
917 {"ml", "; "}, /* mocklisp */
918 {"mm", ".\\\" "}, /* mm-macros t/nroff */
919 {"ms", ".\\\" "}, /* ms-macros t/nroff */
920 {"man", ".\\\" "}, /* man-macros t/nroff */
921 {"1", ".\\\" "}, /* feeble attempt at man pages... */
930 {"p", " * "}, /* pascal */
932 {"pl", "# "}, /* perl (conflict with Prolog) */
933 {"ps", "% "}, /* postscript */
934 {"psw", "% "}, /* postscript wrap */
935 {"pswm", "% "}, /* postscript wrap */
936 {"r", "# "}, /* ratfor */
937 {"rc", " * "}, /* Microsoft Windows resource file */
938 {"red", "% "}, /* psl/rlisp */
940 {"s", "! "}, /* assembler */
943 {"s", "| "}, /* assembler */
946 {"s", "/ "}, /* assembler */
949 {"s", "# "}, /* assembler */
952 {"s", "# "}, /* assembler */
953 {"S", "# "}, /* Macro assembler */
955 {"sh", "# "}, /* shell */
956 {"sl", "% "}, /* psl */
957 {"spec", "-- "}, /* Ada */
958 {"tex", "% "}, /* tex */
959 {"y", " * "}, /* yacc */
960 {"ye", " * "}, /* yacc-efl */
961 {"yr", " * "}, /* yacc-ratfor */
962 {"", "# "}, /* default for empty suffix */
963 {NULL, "# "} /* default for unknown suffix; */
964 /* must always be last */
976 suffix_path = xmalloc (strlen (user) + 5);
977 cp = strrchr (user, '.');
983 * Convert to lower-case, since we are not concerned about the
984 * case-ness of the suffix.
986 (void) strcpy (suffix_path, cp);
987 for (cp = suffix_path; *cp; cp++)
988 if (isupper ((unsigned char) *cp))
990 suffix = suffix_path;
993 suffix = ""; /* will use the default */
996 if (comtable[i].suffix == NULL)
998 /* Default. Note we'll always hit this case before we
1000 retval = comtable[i].comlead;
1003 if (strcmp (suffix, comtable[i].suffix) == 0)
1005 retval = comtable[i].comlead;
1013 /* Create a new RCS file from scratch.
1015 This probably should be moved to rcs.c now that it is called from
1016 places outside import.c.
1018 Return value is 0 for success, or nonzero for failure (in which
1019 case an error message will have already been printed). */
1021 add_rcs_file (message, rcs, user, add_vhead, key_opt,
1022 add_vbranch, vtag, targc, targv,
1023 desctext, desclen, add_logfp)
1024 /* Log message for the addition. Not used if add_vhead == NULL. */
1025 const char *message;
1026 /* Filename of the RCS file to create. */
1028 /* Filename of the file to serve as the contents of the initial
1029 revision. Even if add_vhead is NULL, we use this to determine
1030 the modes to give the new RCS file. */
1033 /* Revision number of head that we are adding. Normally 1.1 but
1034 could be another revision as long as ADD_VBRANCH is a branch
1035 from it. If NULL, then just add an empty file without any
1036 revisions (similar to the one created by "rcs -i"). */
1037 const char *add_vhead;
1039 /* Keyword expansion mode, e.g., "b" for binary. NULL means the
1040 default behavior. */
1041 const char *key_opt;
1043 /* Vendor branch to import to, or NULL if none. If non-NULL, then
1044 vtag should also be non-NULL. */
1045 const char *add_vbranch;
1050 /* If non-NULL, description for the file. If NULL, the description
1052 const char *desctext;
1055 /* Write errors to here as well as via error (), or NULL if we should
1056 use only error (). */
1059 FILE *fprcs, *fpuser;
1063 char altdate1[MAXDATELEN];
1065 int i, ierrno, err = 0;
1068 const char *userfile;
1069 char *free_opt = NULL;
1075 /* Note that as the code stands now, the -k option overrides any
1076 settings in wrappers (whether CVSROOT/cvswrappers, -W, or
1077 whatever). Some have suggested this should be the other way
1078 around. As far as I know the documentation doesn't say one way
1079 or the other. Before making a change of this sort, should think
1080 about what is best, document it (in cvs.texinfo and NEWS), &c. */
1082 if (key_opt == NULL)
1084 if (wrap_name_has (user, WRAP_RCSOPTION))
1086 key_opt = free_opt = wrap_rcsoption (user, 0);
1090 tocvsPath = wrap_tocvs_process_file (user);
1091 userfile = (tocvsPath == NULL ? user : tocvsPath);
1093 /* Opening in text mode is probably never the right thing for the
1094 server (because the protocol encodes text files in a fashion
1095 which does not depend on what the client or server OS is, as
1096 documented in cvsclient.texi), but as long as the server just
1097 runs on unix it is a moot point. */
1099 /* If PreservePermissions is set, then make sure that the file
1100 is a plain file before trying to open it. Longstanding (although
1101 often unpopular) CVS behavior has been to follow symlinks, so we
1102 maintain that behavior if PreservePermissions is not on.
1104 NOTE: this error message used to be `cannot fstat', but is now
1105 `cannot lstat'. I don't see a way around this, since we must
1106 stat the file before opening it. -twp */
1108 if (CVS_LSTAT (userfile, &sb) < 0)
1110 /* not fatal, continue import */
1111 if (add_logfp != NULL)
1112 fperrmsg (add_logfp, 0, errno,
1113 "ERROR: cannot lstat file %s", userfile);
1114 error (0, errno, "cannot lstat file %s", userfile);
1117 file_type = sb.st_mode & S_IFMT;
1120 if (!preserve_perms || file_type == S_IFREG)
1122 fpuser = CVS_FOPEN (userfile,
1123 ((key_opt != NULL && strcmp (key_opt, "b") == 0)
1129 /* not fatal, continue import */
1130 if (add_logfp != NULL)
1131 fperrmsg (add_logfp, 0, errno,
1132 "ERROR: cannot read file %s", userfile);
1133 error (0, errno, "ERROR: cannot read file %s", userfile);
1138 fprcs = CVS_FOPEN (rcs, "w+b");
1142 goto write_error_noclose;
1148 if (add_vhead != NULL)
1150 if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
1155 if (fprintf (fprcs, "head ;\012") < 0)
1159 if (add_vbranch != NULL)
1161 if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
1164 if (fprintf (fprcs, "access ;\012") < 0 ||
1165 fprintf (fprcs, "symbols ") < 0)
1170 for (i = targc - 1; i >= 0; i--)
1172 /* RCS writes the symbols backwards */
1173 assert (add_vbranch != NULL);
1174 if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
1178 if (add_vbranch != NULL)
1180 if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
1183 if (fprintf (fprcs, ";\012") < 0)
1186 if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
1187 /* XXX - make sure @@ processing works in the RCS file */
1188 fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
1193 if (key_opt != NULL && strcmp (key_opt, "kv") != 0)
1195 if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0)
1201 if (fprintf (fprcs, "\012") < 0)
1204 /* Write the revision(s), with the date and author and so on
1205 (that is "delta" rather than "deltatext" from rcsfile(5)). */
1206 if (add_vhead != NULL)
1208 if (use_file_modtime)
1212 ftm = gmtime (&now);
1213 (void) sprintf (altdate1, DATEFORM,
1214 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1215 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1216 ftm->tm_min, ftm->tm_sec);
1217 author = getcaller ();
1219 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1220 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1221 altdate1, author) < 0)
1224 if (fprintf (fprcs, "branches") < 0)
1226 if (add_vbranch != NULL)
1228 if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
1231 if (fprintf (fprcs, ";\012") < 0)
1234 if (fprintf (fprcs, "next ;\012") < 0)
1237 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1238 /* Store initial permissions if necessary. */
1241 if (file_type == S_IFLNK)
1243 char *link = xreadlink (userfile);
1244 if (fprintf (fprcs, "symlink\t@") < 0 ||
1245 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1246 fprintf (fprcs, "@;\012") < 0)
1252 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
1254 if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
1256 if (fprintf (fprcs, "permissions\t%o;\012",
1257 sb.st_mode & 07777) < 0)
1261 case S_IFREG: break;
1264 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1265 if (fprintf (fprcs, "special\t%s %lu;\012",
1266 (file_type == S_IFCHR
1269 (unsigned long) sb.st_rdev) < 0)
1273 "can't import %s: unable to import device files on this system",
1279 "can't import %s: unknown kind of special file",
1286 if (add_vbranch != NULL)
1288 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1289 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1290 altdate1, author) < 0 ||
1291 fprintf (fprcs, "branches ;\012") < 0 ||
1292 fprintf (fprcs, "next ;\012") < 0)
1295 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1296 /* Store initial permissions if necessary. */
1299 if (file_type == S_IFLNK)
1301 char *link = xreadlink (userfile);
1302 if (fprintf (fprcs, "symlink\t@") < 0 ||
1303 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1304 fprintf (fprcs, "@;\012") < 0)
1310 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
1311 fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
1312 fprintf (fprcs, "permissions\t%o;\012",
1313 sb.st_mode & 07777) < 0)
1318 case S_IFREG: break;
1321 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1322 if (fprintf (fprcs, "special\t%s %lu;\012",
1323 (file_type == S_IFCHR
1326 (unsigned long) sb.st_rdev) < 0)
1330 "can't import %s: unable to import device files on this system",
1336 "cannot import %s: special file of unknown type",
1343 if (fprintf (fprcs, "\012") < 0)
1348 /* Now write the description (possibly empty). */
1349 if (fprintf (fprcs, "\012desc\012") < 0 ||
1350 fprintf (fprcs, "@") < 0)
1352 if (desctext != NULL)
1354 /* The use of off_t not size_t for the second argument is very
1355 strange, since we are dealing with something which definitely
1357 if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
1360 if (fprintf (fprcs, "@\012\012\012") < 0)
1363 /* Now write the log messages and contents for the revision(s) (that
1364 is, "deltatext" rather than "delta" from rcsfile(5)). */
1365 if (add_vhead != NULL)
1367 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1368 fprintf (fprcs, "log\012@") < 0)
1370 if (add_vbranch != NULL)
1372 /* We are going to put the log message in the revision on the
1373 branch. So putting it here too seems kind of redundant, I
1374 guess (and that is what CVS has always done, anyway). */
1375 if (fprintf (fprcs, "Initial revision\012") < 0)
1380 if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
1383 if (fprintf (fprcs, "@\012") < 0 ||
1384 fprintf (fprcs, "text\012@") < 0)
1389 /* Now copy over the contents of the file, expanding at signs.
1390 If preserve_perms is set, do this only for regular files. */
1391 if (!preserve_perms || file_type == S_IFREG)
1398 len = fread (buf, 1, sizeof buf, fpuser);
1401 if (ferror (fpuser))
1402 error (1, errno, "cannot read file %s for copying",
1406 if (expand_at_signs (buf, len, fprcs) < 0)
1410 if (fprintf (fprcs, "@\012\012") < 0)
1412 if (add_vbranch != NULL)
1414 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1415 fprintf (fprcs, "log\012@") < 0 ||
1416 expand_at_signs (message,
1417 (off_t) strlen (message), fprcs) < 0 ||
1418 fprintf (fprcs, "@\012text\012") < 0 ||
1419 fprintf (fprcs, "@@\012") < 0)
1424 if (fclose (fprcs) == EOF)
1427 goto write_error_noclose;
1429 /* Close fpuser only if we opened it to begin with. */
1432 if (fclose (fpuser) < 0)
1433 error (0, errno, "cannot close %s", user);
1437 * Fix the modes on the RCS files. The user modes of the original
1438 * user file are propagated to the group and other modes as allowed
1439 * by the repository umask, except that all write permissions are
1442 mode = (sb.st_mode |
1443 (sb.st_mode & S_IRWXU) >> 3 |
1444 (sb.st_mode & S_IRWXU) >> 6) &
1446 ~(S_IWRITE | S_IWGRP | S_IWOTH);
1447 if (chmod (rcs, mode) < 0)
1450 if (add_logfp != NULL)
1451 fperrmsg (add_logfp, 0, ierrno,
1452 "WARNING: cannot change mode of file %s", rcs);
1453 error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
1457 if (unlink_file_dir (tocvsPath) < 0)
1458 error (0, errno, "cannot remove %s", tocvsPath);
1459 if (free_opt != NULL)
1465 if (fclose (fprcs) < 0)
1466 error (0, errno, "cannot close %s", rcs);
1467 write_error_noclose:
1468 if (fclose (fpuser) < 0)
1469 error (0, errno, "cannot close %s", user);
1470 if (add_logfp != NULL)
1471 fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
1472 error (0, ierrno, "ERROR: cannot write file %s", rcs);
1473 if (ierrno == ENOSPC)
1475 if (CVS_UNLINK (rcs) < 0)
1476 error (0, errno, "cannot remove %s", rcs);
1477 if (add_logfp != NULL)
1478 fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
1479 error (1, 0, "ERROR: out of space - aborting");
1483 if (unlink_file_dir (tocvsPath) < 0)
1484 error (0, errno, "cannot remove %s", tocvsPath);
1486 if (free_opt != NULL)
1493 * Write SIZE bytes at BUF to FP, expanding @ signs into double @
1494 * signs. If an error occurs, return a negative value and set errno
1495 * to indicate the error. If not, return a nonnegative value.
1498 expand_at_signs (buf, size, fp)
1503 register const char *cp, *next;
1506 while ((next = memchr (cp, '@', size)) != NULL)
1508 size_t len = ++next - cp;
1509 if (fwrite (cp, 1, len, fp) != len)
1511 if (putc ('@', fp) == EOF)
1517 if (fwrite (cp, 1, size, fp) != size)
1524 * Write an update message to (potentially) the screen and the log file.
1531 if (!really_quiet) /* write to terminal */
1536 cvs_output (buf, 2);
1539 cvs_output (repository + repos_len + 1, 0);
1540 cvs_output ("/", 1);
1542 else if (repository[0] != '\0')
1544 cvs_output (repository, 0);
1545 cvs_output ("/", 1);
1547 cvs_output (fname, 0);
1548 cvs_output ("\n", 1);
1551 if (repos_len) /* write to logfile */
1552 (void) fprintf (logfp, "%c %s/%s\n", ch,
1553 repository + repos_len + 1, fname);
1554 else if (repository[0])
1555 (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
1557 (void) fprintf (logfp, "%c %s\n", ch, fname);
1561 * This is the recursive function that walks the argument directory looking
1562 * for sub-directories that have CVS administration files in them and updates
1565 * Note that we do not follow symbolic links here, which is a feature!
1568 import_descend_dir (message, dir, vtag, targc, targv)
1575 struct saved_cwd cwd;
1582 if (save_cwd (&cwd))
1584 fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
1588 /* Concatenate DIR to the end of REPOSITORY. */
1589 if (repository[0] == '\0')
1591 char *new = xstrdup (dir);
1597 char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
1598 strcpy (new, repository);
1599 (void) strcat (new, "/");
1600 (void) strcat (new, dir);
1605 if (!quiet && !current_parsed_root->isremote)
1606 error (0, 0, "Importing %s", repository);
1608 if ( CVS_CHDIR (dir) < 0)
1611 fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", dir);
1612 error (0, ierrno, "ERROR: cannot chdir to %s", dir);
1616 if (!current_parsed_root->isremote && !isdir (repository))
1618 rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
1619 (void) sprintf (rcs, "%s%s", repository, RCSEXT);
1620 if (isfile (repository) || isfile(rcs))
1622 fperrmsg (logfp, 0, 0,
1623 "ERROR: %s is a file, should be a directory!",
1625 error (0, 0, "ERROR: %s is a file, should be a directory!",
1630 if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
1633 fperrmsg (logfp, 0, ierrno,
1634 "ERROR: cannot mkdir %s -- not added", repository);
1636 "ERROR: cannot mkdir %s -- not added", repository);
1641 err = import_descend (message, vtag, targc, targv);
1645 if ((cp = strrchr (repository, '/')) != NULL)
1648 repository[0] = '\0';
1649 if (restore_cwd (&cwd, NULL))