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 if ((cp = strstr(argv[0], "CVS")) && /* path contains "CVS" AND ... */
166 ((cp == argv[0]) || ISDIRSEP(*(cp-1))) && /* /^CVS/ OR m#/CVS# AND ... */
167 ((*(cp+3) == '\0') || ISDIRSEP(*(cp+3))) /* /CVS$/ OR m#CVS/# */
171 "The word `CVS' is reserved by CVS and may not be used");
172 error (1, 0, "as a directory in a path or as a file name.");
175 for (i = 1; i < argc; i++) /* check the tags for validity */
179 RCS_check_tag (argv[i]);
180 for (j = 1; j < i; j++)
181 if (strcmp (argv[j], argv[i]) == 0)
182 error (1, 0, "tag `%s' was specified more than once", argv[i]);
185 /* XXX - this should be a module, not just a pathname */
186 if (!isabsolute (argv[0]) && pathname_levels (argv[0]) == 0)
188 if (current_parsed_root == NULL)
190 error (0, 0, "missing CVSROOT environment variable\n");
191 error (1, 0, "Set it or specify the '-d' option to %s.",
194 repository = xmalloc (strlen (current_parsed_root->directory)
197 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
198 repos_len = strlen (current_parsed_root->directory);
202 /* It is somewhere between a security hole and "unexpected" to
203 let the client start mucking around outside the cvsroot
204 (wouldn't get the right CVSROOT configuration, &c). */
205 error (1, 0, "directory %s not relative within the repository",
210 * Consistency checks on the specified vendor branch. It must be
211 * composed of only numbers and dots ('.'). Also, for now we only
212 * support branching to a single level, so the specified vendor branch
213 * must only have two dots in it (like "1.1.1").
217 int ret = regcomp (&pat, "^[1-9][0-9]*\\.[1-9][0-9]*\\.[1-9][0-9]*$",
220 if (regexec (&pat, vbranch, 0, NULL, 0))
223 "Only numeric branch specifications with two dots are\n"
224 "supported by import, not `%s'. For example: `1.1.1'.",
230 /* Set vhead to the branch's parent. */
231 vhead = xstrdup (vbranch);
232 cp = strrchr (vhead, '.');
235 #ifdef CLIENT_SUPPORT
236 if (current_parsed_root->isremote)
238 /* For rationale behind calling start_server before do_editor, see
244 if (!server_active && use_editor)
246 do_editor ((char *) NULL, &message,
247 current_parsed_root->isremote ? (char *) NULL : repository,
250 do_verify (&message, repository);
251 msglen = message == NULL ? 0 : strlen (message);
252 if (msglen == 0 || message[msglen - 1] != '\n')
254 char *nm = xmalloc (msglen + 2);
258 (void) strcpy (nm, message);
261 (void) strcat (nm + msglen, "\n");
265 #ifdef CLIENT_SUPPORT
266 if (current_parsed_root->isremote)
270 if (vbranch[0] != '\0')
271 option_with_arg ("-b", vbranch);
272 option_with_arg ("-m", message ? message : "");
273 if (keyword_opt != NULL)
274 option_with_arg ("-k", keyword_opt);
275 /* The only ignore processing which takes place on the server side
276 is the CVSROOT/cvsignore file. But if the user specified -I !,
277 the documented behavior is to not process said file. */
278 if (ign_inhibit_server)
287 for (i = 0; i < argc; ++i)
292 client_import_setup (repository);
293 err = import_descend (message, argv[1], argc - 2, argv + 2);
294 client_import_done ();
300 send_to_server ("import\012", 0);
301 err += get_responses_and_close ();
306 if (!safe_location ( NULL ))
308 error (1, 0, "attempt to import the repository");
312 * Make all newly created directories writable. Should really use a more
313 * sophisticated security mechanism here.
315 (void) umask (cvsumask);
316 make_directories (repository);
318 /* Create the logfile that will be logged upon completion */
319 if ((logfp = cvs_temp_file (&tmpfile)) == NULL)
320 error (1, errno, "cannot create temporary file `%s'",
321 tmpfile ? tmpfile : "(null)");
322 /* On systems where we can unlink an open file, do so, so it will go
323 away no matter how we exit. FIXME-maybe: Should be checking for
324 errors but I'm not sure which error(s) we get if we are on a system
325 where one can't unlink open files. */
326 (void) CVS_UNLINK (tmpfile);
327 (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
328 (void) fprintf (logfp, "Release Tags:\t");
329 for (i = 2; i < argc; i++)
330 (void) fprintf (logfp, "%s\n\t\t", argv[i]);
331 (void) fprintf (logfp, "\n");
334 err = import_descend (message, argv[1], argc - 2, argv + 2);
341 cvs_output_tagged ("+importmergecmd", NULL);
342 cvs_output_tagged ("newline", NULL);
343 sprintf (buf, "%d", conflicts);
344 cvs_output_tagged ("conflicts", buf);
345 cvs_output_tagged ("text", " conflicts created by this import.");
346 cvs_output_tagged ("newline", NULL);
347 cvs_output_tagged ("text",
348 "Use the following command to help the merge:");
349 cvs_output_tagged ("newline", NULL);
350 cvs_output_tagged ("newline", NULL);
351 cvs_output_tagged ("text", "\t");
352 cvs_output_tagged ("text", program_name);
353 if (CVSroot_cmdline != NULL)
355 cvs_output_tagged ("text", " -d ");
356 cvs_output_tagged ("text", CVSroot_cmdline);
358 cvs_output_tagged ("text", " checkout -j");
359 cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
360 cvs_output_tagged ("text", " -j");
361 cvs_output_tagged ("mergetag2", argv[2]);
362 cvs_output_tagged ("text", " ");
363 cvs_output_tagged ("repository", argv[0]);
364 cvs_output_tagged ("newline", NULL);
365 cvs_output_tagged ("newline", NULL);
366 cvs_output_tagged ("-importmergecmd", NULL);
369 /* FIXME: I'm not sure whether we need to put this information
370 into the loginfo. If we do, then note that it does not
371 report any required -d option. There is no particularly
372 clean way to tell the server about the -d option used by
374 (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
376 (void) fprintf (logfp,
377 "Use the following command to help the merge:\n\n");
378 (void) fprintf (logfp, "\t%s checkout ", program_name);
379 (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
380 argv[1], argv[1], argv[0]);
385 cvs_output ("\nNo conflicts created by this import\n\n", 0);
386 (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
390 * Write out the logfile and clean up.
395 p->delproc = update_delproc;
396 p->key = xstrdup ("- Imported sources");
397 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
399 li->tag = xstrdup (vbranch);
400 li->rev_old = li->rev_new = NULL;
402 (void) addnode (ulist, p);
403 Update_Logfile (repository, message, logfp, ulist);
405 if (fclose (logfp) < 0)
406 error (0, errno, "error closing %s", tmpfile);
408 /* Make sure the temporary file goes away, even on systems that don't let
409 you delete a file that's in use. */
410 if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
411 error (0, errno, "cannot remove %s", tmpfile);
423 /* Process all the files in ".", then descend into other directories.
424 Returns 0 for success, or >0 on error (in which case a message
425 will have been printed). */
427 import_descend (message, vtag, targc, targv)
436 List *dirlist = NULL;
438 /* first, load up any per-directory ignore lists */
439 ign_add_file (CVSDOTIGNORE, 1);
440 wrap_add_file (CVSDOTWRAPPER, 1);
442 if (!current_parsed_root->isremote)
443 lock_dir_for_write (repository);
445 if ((dirp = CVS_OPENDIR (".")) == NULL)
447 error (0, errno, "cannot open directory");
453 while ((dp = CVS_READDIR (dirp)) != NULL)
455 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
456 goto one_more_time_boys;
458 /* CVS directories are created in the temp directory by
459 server.c because it doesn't special-case import. So
460 don't print a message about them, regardless of -I!. */
461 if (server_active && strcmp (dp->d_name, CVSADM) == 0)
462 goto one_more_time_boys;
464 if (ign_name (dp->d_name))
466 add_log ('I', dp->d_name);
467 goto one_more_time_boys;
472 (dp->d_type == DT_DIR
473 || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
477 && !wrap_name_has (dp->d_name, WRAP_TOCVS)
486 n->key = xstrdup (dp->d_name);
492 || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
498 add_log ('L', dp->d_name);
503 #ifdef CLIENT_SUPPORT
504 if (current_parsed_root->isremote)
505 err += client_process_import_file (message, dp->d_name,
508 keyword_opt != NULL &&
509 keyword_opt[0] == 'b',
513 err += process_import_file (message, dp->d_name,
521 error (0, errno, "cannot read directory");
524 (void) CVS_CLOSEDIR (dirp);
527 if (!current_parsed_root->isremote)
534 head = dirlist->list;
535 for (p = head->next; p != head; p = p->next)
537 err += import_descend_dir (message, p->key, vtag, targc, targv);
547 * Process the argument import file.
550 process_import_file (message, vfile, vtag, targc, targv)
560 rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT)
562 (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
567 attic_name = xmalloc (strlen (repository) + strlen (vfile) +
568 sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
569 (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
571 if (!isfile (attic_name))
574 char *free_opt = NULL;
575 char *our_opt = keyword_opt;
579 * A new import source file; it doesn't exist as a ,v within the
580 * repository nor in the Attic -- create it anew.
582 add_log ('N', vfile);
584 #ifdef SERVER_SUPPORT
585 /* The most reliable information on whether the file is binary
586 is what the client told us. That is because if the client had
587 the wrong idea about binaryness, it corrupted the file, so
588 we might as well believe the client. */
594 /* Reading all the entries for each file is fairly silly, and
595 probably slow. But I am too lazy at the moment to do
597 entries = Entries_Open (0, NULL);
598 node = findnode_fn (entries, vfile);
601 Entnode *entdata = node->data;
603 if (entdata->type == ENT_FILE)
605 assert (entdata->options[0] == '-'
606 && entdata->options[1] == 'k');
607 our_opt = xstrdup (entdata->options + 2);
611 Entries_Close (entries);
615 retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
616 vbranch, vtag, targc, targv,
618 if (free_opt != NULL)
629 * an rcs file exists. have to do things the official, slow, way.
631 return (update_rcs_file (message, vfile, vtag, targc, targv, inattic));
635 * The RCS file exists; update it by adding the new import file to the
636 * (possibly already existing) vendor branch.
639 update_rcs_file (message, vfile, vtag, targc, targv, inattic)
651 struct file_info finfo;
653 memset (&finfo, 0, sizeof finfo);
655 /* Not used, so don't worry about it. */
656 finfo.update_dir = NULL;
657 finfo.fullname = finfo.file;
658 finfo.repository = repository;
659 finfo.entries = NULL;
661 vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL,
663 if (vers->vn_rcs != NULL
664 && !RCS_isdead(vers->srcfile, vers->vn_rcs))
669 * The rcs file does have a revision on the vendor branch. Compare
670 * this revision with the import file; if they match exactly, there
671 * is no need to install the new import file as a new revision to the
672 * branch. Just tag the revision with the new import tags.
674 * This is to try to cut down the number of "C" conflict messages for
675 * locally modified import source files.
677 tocvsPath = wrap_tocvs_process_file (vfile);
678 /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
680 expand = vers->srcfile->expand != NULL &&
681 vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
682 different = RCS_cmp_file( vers->srcfile, vers->vn_rcs, (char **)NULL,
683 (char *)NULL, expand, vfile );
685 if (unlink_file_dir (tocvsPath) < 0)
686 error (0, errno, "cannot remove %s", tocvsPath);
693 * The two files are identical. Just update the tags, print the
694 * "U", signifying that the file has changed, but needs no
695 * attention, and we're done.
697 if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
699 add_log ('U', vfile);
705 /* We may have failed to parse the RCS file; check just in case */
706 if (vers->srcfile == NULL ||
707 add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
708 add_tags (vers->srcfile, vfile, vtag, targc, targv))
714 if (vers->srcfile->branch == NULL || inattic ||
715 strcmp (vers->srcfile->branch, vbranch) != 0)
722 add_log (letter, vfile);
729 * Add the revision to the vendor branch
732 add_rev (message, rcs, vfile, vers)
738 int locked, status, ierrno;
747 /* Before RCS_lock existed, we were directing stdout, as well as
748 stderr, from the RCS command, to DEVNULL. I wouldn't guess that
749 was necessary, but I don't know for sure. */
750 /* Earlier versions of this function printed a `fork failed' error
751 when RCS_lock returned an error code. That's not appropriate
752 now that RCS_lock is librarified, but should the error text be
754 if (RCS_lock (rcs, vbranch, 1) != 0)
757 RCS_rewrite (rcs, NULL, NULL);
759 tocvsPath = wrap_tocvs_process_file (vfile);
761 status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
763 (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
764 | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
767 if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
768 error (0, errno, "cannot remove %s", tocvsPath);
774 fperrmsg (logfp, 0, status == -1 ? ierrno : 0,
775 "ERROR: Check-in of %s failed", rcs->path);
776 error (0, status == -1 ? ierrno : 0,
777 "ERROR: Check-in of %s failed", rcs->path);
781 (void) RCS_unlock(rcs, vbranch, 0);
782 RCS_rewrite (rcs, NULL, NULL);
790 * Add the vendor branch tag and all the specified import release tags to the
791 * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
792 * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
796 add_tags (rcs, vfile, vtag, targc, targv)
806 struct file_info finfo;
811 if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
814 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
815 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
816 error (0, retcode == -1 ? ierrno : 0,
817 "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
820 RCS_rewrite (rcs, NULL, NULL);
822 memset (&finfo, 0, sizeof finfo);
824 /* Not used, so don't worry about it. */
825 finfo.update_dir = NULL;
826 finfo.fullname = finfo.file;
827 finfo.repository = repository;
828 finfo.entries = NULL;
830 vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
831 for (i = 0; i < targc; i++)
833 if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
834 RCS_rewrite (rcs, NULL, NULL);
838 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
839 "WARNING: Couldn't add tag %s to %s", targv[i],
841 error (0, retcode == -1 ? ierrno : 0,
842 "WARNING: Couldn't add tag %s to %s", targv[i],
851 * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
855 char *suffix, *comlead;
858 static const struct compair comtable[] =
862 * comtable pairs each filename suffix with a comment leader. The comment
863 * leader is placed before each line generated by the $Log keyword. This
864 * table is used to guess the proper comment leader from the working file's
865 * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
866 * languages without multiline comments; for others they are optional.
868 * I believe that the comment leader is unused if you are using RCS 5.7, which
869 * decides what leader to use based on the text surrounding the $Log keyword
870 * rather than a specified comment leader.
872 {"a", "-- "}, /* Ada */
875 {"asm", ";; "}, /* assembler (MS-DOS) */
876 {"ads", "-- "}, /* Ada */
877 {"bas", "' "}, /* Visual Basic code */
878 {"bat", ":: "}, /* batch (MS-DOS) */
879 {"body", "-- "}, /* Ada */
880 {"c", " * "}, /* C */
881 {"c++", "// "}, /* C++ in all its infinite guises */
885 {"m", "// "}, /* Objective-C */
886 {"cl", ";;; "}, /* Common Lisp */
887 {"cmd", ":: "}, /* command (OS/2) */
888 {"cmf", "c "}, /* CM Fortran */
889 {"cs", " * "}, /* C* */
890 {"csh", "# "}, /* shell */
891 {"dlg", " * "}, /* MS Windows dialog file */
892 {"e", "# "}, /* efl */
893 {"epsf", "% "}, /* encapsulated postscript */
894 {"epsi", "% "}, /* encapsulated postscript */
895 {"el", "; "}, /* Emacs Lisp */
896 {"f", "c "}, /* Fortran */
898 {"frm", "' "}, /* Visual Basic form */
899 {"h", " * "}, /* C-header */
900 {"hh", "// "}, /* C++ header */
903 {"in", "# "}, /* for Makefile.in */
904 {"l", " * "}, /* lex (conflict between lex and
906 {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
908 {"mak", "# "}, /* makefile, e.g. Visual C++ */
909 {"me", ".\\\" "}, /* me-macros t/nroff */
910 {"ml", "; "}, /* mocklisp */
911 {"mm", ".\\\" "}, /* mm-macros t/nroff */
912 {"ms", ".\\\" "}, /* ms-macros t/nroff */
913 {"man", ".\\\" "}, /* man-macros t/nroff */
914 {"1", ".\\\" "}, /* feeble attempt at man pages... */
923 {"p", " * "}, /* pascal */
925 {"pl", "# "}, /* perl (conflict with Prolog) */
926 {"ps", "% "}, /* postscript */
927 {"psw", "% "}, /* postscript wrap */
928 {"pswm", "% "}, /* postscript wrap */
929 {"r", "# "}, /* ratfor */
930 {"rc", " * "}, /* Microsoft Windows resource file */
931 {"red", "% "}, /* psl/rlisp */
933 {"s", "! "}, /* assembler */
936 {"s", "| "}, /* assembler */
939 {"s", "/ "}, /* assembler */
942 {"s", "# "}, /* assembler */
945 {"s", "# "}, /* assembler */
946 {"S", "# "}, /* Macro assembler */
948 {"sh", "# "}, /* shell */
949 {"sl", "% "}, /* psl */
950 {"spec", "-- "}, /* Ada */
951 {"tex", "% "}, /* tex */
952 {"y", " * "}, /* yacc */
953 {"ye", " * "}, /* yacc-efl */
954 {"yr", " * "}, /* yacc-ratfor */
955 {"", "# "}, /* default for empty suffix */
956 {NULL, "# "} /* default for unknown suffix; */
957 /* must always be last */
969 suffix_path = xmalloc (strlen (user) + 5);
970 cp = strrchr (user, '.');
976 * Convert to lower-case, since we are not concerned about the
977 * case-ness of the suffix.
979 (void) strcpy (suffix_path, cp);
980 for (cp = suffix_path; *cp; cp++)
981 if (isupper ((unsigned char) *cp))
983 suffix = suffix_path;
986 suffix = ""; /* will use the default */
989 if (comtable[i].suffix == NULL)
991 /* Default. Note we'll always hit this case before we
993 retval = comtable[i].comlead;
996 if (strcmp (suffix, comtable[i].suffix) == 0)
998 retval = comtable[i].comlead;
1006 /* Create a new RCS file from scratch.
1008 This probably should be moved to rcs.c now that it is called from
1009 places outside import.c.
1011 Return value is 0 for success, or nonzero for failure (in which
1012 case an error message will have already been printed). */
1014 add_rcs_file (message, rcs, user, add_vhead, key_opt,
1015 add_vbranch, vtag, targc, targv,
1016 desctext, desclen, add_logfp)
1017 /* Log message for the addition. Not used if add_vhead == NULL. */
1018 const char *message;
1019 /* Filename of the RCS file to create. */
1021 /* Filename of the file to serve as the contents of the initial
1022 revision. Even if add_vhead is NULL, we use this to determine
1023 the modes to give the new RCS file. */
1026 /* Revision number of head that we are adding. Normally 1.1 but
1027 could be another revision as long as ADD_VBRANCH is a branch
1028 from it. If NULL, then just add an empty file without any
1029 revisions (similar to the one created by "rcs -i"). */
1030 const char *add_vhead;
1032 /* Keyword expansion mode, e.g., "b" for binary. NULL means the
1033 default behavior. */
1034 const char *key_opt;
1036 /* Vendor branch to import to, or NULL if none. If non-NULL, then
1037 vtag should also be non-NULL. */
1038 const char *add_vbranch;
1043 /* If non-NULL, description for the file. If NULL, the description
1045 const char *desctext;
1048 /* Write errors to here as well as via error (), or NULL if we should
1049 use only error (). */
1052 FILE *fprcs, *fpuser;
1056 char altdate1[MAXDATELEN];
1058 int i, ierrno, err = 0;
1061 const char *userfile;
1062 char *free_opt = NULL;
1068 /* Note that as the code stands now, the -k option overrides any
1069 settings in wrappers (whether CVSROOT/cvswrappers, -W, or
1070 whatever). Some have suggested this should be the other way
1071 around. As far as I know the documentation doesn't say one way
1072 or the other. Before making a change of this sort, should think
1073 about what is best, document it (in cvs.texinfo and NEWS), &c. */
1075 if (key_opt == NULL)
1077 if (wrap_name_has (user, WRAP_RCSOPTION))
1079 key_opt = free_opt = wrap_rcsoption (user, 0);
1083 tocvsPath = wrap_tocvs_process_file (user);
1084 userfile = (tocvsPath == NULL ? user : tocvsPath);
1086 /* Opening in text mode is probably never the right thing for the
1087 server (because the protocol encodes text files in a fashion
1088 which does not depend on what the client or server OS is, as
1089 documented in cvsclient.texi), but as long as the server just
1090 runs on unix it is a moot point. */
1092 /* If PreservePermissions is set, then make sure that the file
1093 is a plain file before trying to open it. Longstanding (although
1094 often unpopular) CVS behavior has been to follow symlinks, so we
1095 maintain that behavior if PreservePermissions is not on.
1097 NOTE: this error message used to be `cannot fstat', but is now
1098 `cannot lstat'. I don't see a way around this, since we must
1099 stat the file before opening it. -twp */
1101 if (CVS_LSTAT (userfile, &sb) < 0)
1103 /* not fatal, continue import */
1104 if (add_logfp != NULL)
1105 fperrmsg (add_logfp, 0, errno,
1106 "ERROR: cannot lstat file %s", userfile);
1107 error (0, errno, "cannot lstat file %s", userfile);
1110 file_type = sb.st_mode & S_IFMT;
1113 if (!preserve_perms || file_type == S_IFREG)
1115 fpuser = CVS_FOPEN (userfile,
1116 ((key_opt != NULL && strcmp (key_opt, "b") == 0)
1122 /* not fatal, continue import */
1123 if (add_logfp != NULL)
1124 fperrmsg (add_logfp, 0, errno,
1125 "ERROR: cannot read file %s", userfile);
1126 error (0, errno, "ERROR: cannot read file %s", userfile);
1131 fprcs = CVS_FOPEN (rcs, "w+b");
1135 goto write_error_noclose;
1141 if (add_vhead != NULL)
1143 if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
1148 if (fprintf (fprcs, "head ;\012") < 0)
1152 if (add_vbranch != NULL)
1154 if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
1157 if (fprintf (fprcs, "access ;\012") < 0 ||
1158 fprintf (fprcs, "symbols ") < 0)
1163 for (i = targc - 1; i >= 0; i--)
1165 /* RCS writes the symbols backwards */
1166 assert (add_vbranch != NULL);
1167 if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
1171 if (add_vbranch != NULL)
1173 if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
1176 if (fprintf (fprcs, ";\012") < 0)
1179 if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
1180 /* XXX - make sure @@ processing works in the RCS file */
1181 fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
1186 if (key_opt != NULL && strcmp (key_opt, "kv") != 0)
1188 if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0)
1194 if (fprintf (fprcs, "\012") < 0)
1197 /* Write the revision(s), with the date and author and so on
1198 (that is "delta" rather than "deltatext" from rcsfile(5)). */
1199 if (add_vhead != NULL)
1201 if (use_file_modtime)
1205 ftm = gmtime (&now);
1206 (void) sprintf (altdate1, DATEFORM,
1207 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
1208 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
1209 ftm->tm_min, ftm->tm_sec);
1210 author = getcaller ();
1212 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1213 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1214 altdate1, author) < 0)
1217 if (fprintf (fprcs, "branches") < 0)
1219 if (add_vbranch != NULL)
1221 if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
1224 if (fprintf (fprcs, ";\012") < 0)
1227 if (fprintf (fprcs, "next ;\012") < 0)
1230 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1231 /* Store initial permissions if necessary. */
1234 if (file_type == S_IFLNK)
1236 char *link = xreadlink (userfile);
1237 if (fprintf (fprcs, "symlink\t@") < 0 ||
1238 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1239 fprintf (fprcs, "@;\012") < 0)
1245 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
1247 if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
1249 if (fprintf (fprcs, "permissions\t%o;\012",
1250 sb.st_mode & 07777) < 0)
1254 case S_IFREG: break;
1257 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1258 if (fprintf (fprcs, "special\t%s %lu;\012",
1259 (file_type == S_IFCHR
1262 (unsigned long) sb.st_rdev) < 0)
1266 "can't import %s: unable to import device files on this system",
1272 "can't import %s: unknown kind of special file",
1279 if (add_vbranch != NULL)
1281 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1282 fprintf (fprcs, "date %s; author %s; state Exp;\012",
1283 altdate1, author) < 0 ||
1284 fprintf (fprcs, "branches ;\012") < 0 ||
1285 fprintf (fprcs, "next ;\012") < 0)
1288 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1289 /* Store initial permissions if necessary. */
1292 if (file_type == S_IFLNK)
1294 char *link = xreadlink (userfile);
1295 if (fprintf (fprcs, "symlink\t@") < 0 ||
1296 expand_at_signs (link, strlen (link), fprcs) < 0 ||
1297 fprintf (fprcs, "@;\012") < 0)
1303 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
1304 fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
1305 fprintf (fprcs, "permissions\t%o;\012",
1306 sb.st_mode & 07777) < 0)
1311 case S_IFREG: break;
1314 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1315 if (fprintf (fprcs, "special\t%s %lu;\012",
1316 (file_type == S_IFCHR
1319 (unsigned long) sb.st_rdev) < 0)
1323 "can't import %s: unable to import device files on this system",
1329 "cannot import %s: special file of unknown type",
1336 if (fprintf (fprcs, "\012") < 0)
1341 /* Now write the description (possibly empty). */
1342 if (fprintf (fprcs, "\012desc\012") < 0 ||
1343 fprintf (fprcs, "@") < 0)
1345 if (desctext != NULL)
1347 /* The use of off_t not size_t for the second argument is very
1348 strange, since we are dealing with something which definitely
1350 if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
1353 if (fprintf (fprcs, "@\012\012\012") < 0)
1356 /* Now write the log messages and contents for the revision(s) (that
1357 is, "deltatext" rather than "delta" from rcsfile(5)). */
1358 if (add_vhead != NULL)
1360 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
1361 fprintf (fprcs, "log\012@") < 0)
1363 if (add_vbranch != NULL)
1365 /* We are going to put the log message in the revision on the
1366 branch. So putting it here too seems kind of redundant, I
1367 guess (and that is what CVS has always done, anyway). */
1368 if (fprintf (fprcs, "Initial revision\012") < 0)
1373 if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
1376 if (fprintf (fprcs, "@\012") < 0 ||
1377 fprintf (fprcs, "text\012@") < 0)
1382 /* Now copy over the contents of the file, expanding at signs.
1383 If preserve_perms is set, do this only for regular files. */
1384 if (!preserve_perms || file_type == S_IFREG)
1391 len = fread (buf, 1, sizeof buf, fpuser);
1394 if (ferror (fpuser))
1395 error (1, errno, "cannot read file %s for copying",
1399 if (expand_at_signs (buf, len, fprcs) < 0)
1403 if (fprintf (fprcs, "@\012\012") < 0)
1405 if (add_vbranch != NULL)
1407 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
1408 fprintf (fprcs, "log\012@") < 0 ||
1409 expand_at_signs (message,
1410 (off_t) strlen (message), fprcs) < 0 ||
1411 fprintf (fprcs, "@\012text\012") < 0 ||
1412 fprintf (fprcs, "@@\012") < 0)
1417 if (fclose (fprcs) == EOF)
1420 goto write_error_noclose;
1422 /* Close fpuser only if we opened it to begin with. */
1425 if (fclose (fpuser) < 0)
1426 error (0, errno, "cannot close %s", user);
1430 * Fix the modes on the RCS files. The user modes of the original
1431 * user file are propagated to the group and other modes as allowed
1432 * by the repository umask, except that all write permissions are
1435 mode = (sb.st_mode |
1436 (sb.st_mode & S_IRWXU) >> 3 |
1437 (sb.st_mode & S_IRWXU) >> 6) &
1439 ~(S_IWRITE | S_IWGRP | S_IWOTH);
1440 if (chmod (rcs, mode) < 0)
1443 if (add_logfp != NULL)
1444 fperrmsg (add_logfp, 0, ierrno,
1445 "WARNING: cannot change mode of file %s", rcs);
1446 error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
1450 if (unlink_file_dir (tocvsPath) < 0)
1451 error (0, errno, "cannot remove %s", tocvsPath);
1452 if (free_opt != NULL)
1458 if (fclose (fprcs) < 0)
1459 error (0, errno, "cannot close %s", rcs);
1460 write_error_noclose:
1461 if (fclose (fpuser) < 0)
1462 error (0, errno, "cannot close %s", user);
1463 if (add_logfp != NULL)
1464 fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
1465 error (0, ierrno, "ERROR: cannot write file %s", rcs);
1466 if (ierrno == ENOSPC)
1468 if (CVS_UNLINK (rcs) < 0)
1469 error (0, errno, "cannot remove %s", rcs);
1470 if (add_logfp != NULL)
1471 fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
1472 error (1, 0, "ERROR: out of space - aborting");
1476 if (unlink_file_dir (tocvsPath) < 0)
1477 error (0, errno, "cannot remove %s", tocvsPath);
1479 if (free_opt != NULL)
1486 * Write SIZE bytes at BUF to FP, expanding @ signs into double @
1487 * signs. If an error occurs, return a negative value and set errno
1488 * to indicate the error. If not, return a nonnegative value.
1491 expand_at_signs (buf, size, fp)
1496 register const char *cp, *next;
1499 while ((next = memchr (cp, '@', size)) != NULL)
1501 size_t len = ++next - cp;
1502 if (fwrite (cp, 1, len, fp) != len)
1504 if (putc ('@', fp) == EOF)
1510 if (fwrite (cp, 1, size, fp) != size)
1517 * Write an update message to (potentially) the screen and the log file.
1524 if (!really_quiet) /* write to terminal */
1529 cvs_output (buf, 2);
1532 cvs_output (repository + repos_len + 1, 0);
1533 cvs_output ("/", 1);
1535 else if (repository[0] != '\0')
1537 cvs_output (repository, 0);
1538 cvs_output ("/", 1);
1540 cvs_output (fname, 0);
1541 cvs_output ("\n", 1);
1544 if (repos_len) /* write to logfile */
1545 (void) fprintf (logfp, "%c %s/%s\n", ch,
1546 repository + repos_len + 1, fname);
1547 else if (repository[0])
1548 (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
1550 (void) fprintf (logfp, "%c %s\n", ch, fname);
1554 * This is the recursive function that walks the argument directory looking
1555 * for sub-directories that have CVS administration files in them and updates
1558 * Note that we do not follow symbolic links here, which is a feature!
1561 import_descend_dir (message, dir, vtag, targc, targv)
1568 struct saved_cwd cwd;
1575 if (save_cwd (&cwd))
1577 fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
1581 /* Concatenate DIR to the end of REPOSITORY. */
1582 if (repository[0] == '\0')
1584 char *new = xstrdup (dir);
1590 char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
1591 strcpy (new, repository);
1592 (void) strcat (new, "/");
1593 (void) strcat (new, dir);
1598 if (!quiet && !current_parsed_root->isremote)
1599 error (0, 0, "Importing %s", repository);
1601 if ( CVS_CHDIR (dir) < 0)
1604 fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
1605 error (0, ierrno, "ERROR: cannot chdir to %s", repository);
1609 if (!current_parsed_root->isremote && !isdir (repository))
1611 rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
1612 (void) sprintf (rcs, "%s%s", repository, RCSEXT);
1613 if (isfile (repository) || isfile(rcs))
1615 fperrmsg (logfp, 0, 0,
1616 "ERROR: %s is a file, should be a directory!",
1618 error (0, 0, "ERROR: %s is a file, should be a directory!",
1623 if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
1626 fperrmsg (logfp, 0, ierrno,
1627 "ERROR: cannot mkdir %s -- not added", repository);
1629 "ERROR: cannot mkdir %s -- not added", repository);
1634 err = import_descend (message, vtag, targc, targv);
1638 if ((cp = strrchr (repository, '/')) != NULL)
1641 repository[0] = '\0';
1642 if (restore_cwd (&cwd, NULL))