summaryrefslogtreecommitdiff
path: root/gnu/usr.bin
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>1999-06-16 14:02:21 +0000
committerMarc Espie <espie@cvs.openbsd.org>1999-06-16 14:02:21 +0000
commit2810ed462ee6cd7f96afc43b988e660da74da548 (patch)
treead31db4c3190f540434775d9e724dc1dc2125c9e /gnu/usr.bin
parent2e0f656a249424dac2245971ac28096ec191dd69 (diff)
ARCH -> __ARCH_
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/cvs/src/import.c1057
1 files changed, 736 insertions, 321 deletions
diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c
index 95d3c4338d0..dcb35d4b818 100644
--- a/gnu/usr.bin/cvs/src/import.c
+++ b/gnu/usr.bin/cvs/src/import.c
@@ -3,7 +3,7 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*
* "import" checks in the vendor release located in the current directory into
* the CVS source repository. The CVS vendor branch support is utilized.
@@ -17,21 +17,13 @@
*/
#include "cvs.h"
-#include "save-cwd.h"
-
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)import.c 1.63 94/09/30 $";
-USE(rcsid);
-#endif
-
-#define FILE_HOLDER ".#cvsxxx"
+#include "savecwd.h"
+#include <assert.h>
static char *get_comment PROTO((char *user));
-static int add_rcs_file PROTO((char *message, char *rcs, char *user, char *vtag,
- int targc, char *targv[]));
-static int expand_at_signs PROTO((char *buf, off_t size, FILE *fp));
-static int add_rev PROTO((char *message, char *rcs, char *vfile, char *vers));
-static int add_tags PROTO((char *rcs, char *vfile, char *vtag, int targc,
+static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
+ char *vers));
+static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
char *targv[]));
static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]));
static int import_descend_dir PROTO((char *message, char *dir, char *vtag,
@@ -43,10 +35,10 @@ static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int ta
static void add_log PROTO((int ch, char *fname));
static int repos_len;
-static char vhead[50];
-static char vbranch[50];
+static char *vhead;
+static char *vbranch;
static FILE *logfp;
-static char repository[PATH_MAX];
+static char *repository;
static int conflicts;
static int use_file_modtime;
static char *keyword_opt = NULL;
@@ -61,6 +53,7 @@ static const char *const import_usage[] =
"\t-b bra\tVendor branch id.\n",
"\t-m msg\tLog message.\n",
"\t-W spec\tWrappers specification line.\n",
+ "(Specify the --help global option for a list of other help options)\n",
NULL
};
@@ -70,11 +63,12 @@ import (argc, argv)
char **argv;
{
char *message = NULL;
- char tmpfile[L_tmpnam+1];
+ char *tmpfile;
char *cp;
int i, c, msglen, err;
List *ulist;
Node *p;
+ struct logfile_info *li;
if (argc == -1)
usage (import_usage);
@@ -82,9 +76,9 @@ import (argc, argv)
ign_setup ();
wrap_setup ();
- (void) strcpy (vbranch, CVSBRANCH);
- optind = 1;
- while ((c = getopt (argc, argv, "Qqdb:m:I:k:W:")) != -1)
+ vbranch = xstrdup (CVSBRANCH);
+ optind = 0;
+ while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1)
{
switch (c)
{
@@ -100,16 +94,28 @@ import (argc, argv)
command_name);
break;
case 'd':
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* CVS 1.10 and older clients will send this, but it
+ doesn't do any good. So tell the user we can't
+ cope, rather than silently losing. */
+ error (0, 0,
+ "warning: not setting the time of import from the file");
+ error (0, 0, "due to client limitations");
+ }
+#endif
use_file_modtime = 1;
break;
case 'b':
- (void) strcpy (vbranch, optarg);
+ free (vbranch);
+ vbranch = xstrdup (optarg);
break;
case 'm':
#ifdef FORCE_USE_EDITOR
- use_editor = TRUE;
+ use_editor = 1;
#else
- use_editor = FALSE;
+ use_editor = 0;
#endif
message = xstrdup(optarg);
break;
@@ -120,7 +126,7 @@ import (argc, argv)
/* RCS_check_kflag returns strings of the form -kxx. We
only use it for validation, so we can free the value
as soon as it is returned. */
- free (RCS_check_kflag(optarg));
+ free (RCS_check_kflag (optarg));
keyword_opt = optarg;
break;
case 'W':
@@ -137,23 +143,47 @@ import (argc, argv)
if (argc < 3)
usage (import_usage);
+#ifdef SERVER_SUPPORT
+ /* This is for handling the Checkin-time request. It might seem a
+ bit odd to enable the use_file_modtime code even in the case
+ where Checkin-time was not sent for a particular file. The
+ effect is that we use the time of upload, rather than the time
+ when we call RCS_checkin. Since those times are both during
+ CVS's run, that seems OK, and it is easier to implement than
+ putting the "was Checkin-time sent" flag in CVS/Entries or some
+ such place. */
+
+ if (server_active)
+ use_file_modtime = 1;
+#endif
+
for (i = 1; i < argc; i++) /* check the tags for validity */
+ {
+ int j;
+
RCS_check_tag (argv[i]);
+ for (j = 1; j < i; j++)
+ if (strcmp (argv[j], argv[i]) == 0)
+ error (1, 0, "tag `%s' was specified more than once", argv[i]);
+ }
/* XXX - this should be a module, not just a pathname */
if (! isabsolute (argv[0]))
{
- if (CVSroot == NULL)
+ if (CVSroot_directory == NULL)
{
error (0, 0, "missing CVSROOT environment variable\n");
error (1, 0, "Set it or specify the '-d' option to %s.",
program_name);
}
- (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
- repos_len = strlen (CVSroot);
+ repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0])
+ + 10);
+ (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
+ repos_len = strlen (CVSroot_directory);
}
else
{
+ repository = xmalloc (strlen (argv[0]) + 5);
(void) strcpy (repository, argv[0]);
repos_len = 0;
}
@@ -165,20 +195,19 @@ import (argc, argv)
* must only have two dots in it (like "1.1.1").
*/
for (cp = vbranch; *cp != '\0'; cp++)
- if (!isdigit (*cp) && *cp != '.')
+ if (!isdigit ((unsigned char) *cp) && *cp != '.')
error (1, 0, "%s is not a numeric branch", vbranch);
if (numdots (vbranch) != 2)
error (1, 0, "Only branches with two dots are supported: %s", vbranch);
- (void) strcpy (vhead, vbranch);
+ vhead = xstrdup (vbranch);
cp = strrchr (vhead, '.');
*cp = '\0';
#ifdef CLIENT_SUPPORT
if (client_active)
{
- /* Do this now; don't ask for a log message if we can't talk to the
- server. But if there is a syntax error in the options, give
- an error message without connecting. */
+ /* For rationale behind calling start_server before do_editor, see
+ commit.c */
start_server ();
}
#endif
@@ -186,13 +215,14 @@ import (argc, argv)
if (use_editor)
{
do_editor ((char *) NULL, &message, repository,
- (List *) NULL);
+ (List *) NULL);
}
-
+ do_verify (message, repository);
msglen = message == NULL ? 0 : strlen (message);
if (msglen == 0 || message[msglen - 1] != '\n')
{
char *nm = xmalloc (msglen + 2);
+ *nm = '\0';
if (message != NULL)
{
(void) strcpy (nm, message);
@@ -207,17 +237,21 @@ import (argc, argv)
{
int err;
- ign_setup ();
-
- if (use_file_modtime)
- send_arg("-d");
-
if (vbranch[0] != '\0')
option_with_arg ("-b", vbranch);
if (message)
option_with_arg ("-m", message);
if (keyword_opt != NULL)
option_with_arg ("-k", keyword_opt);
+ /* The only ignore processing which takes place on the server side
+ is the CVSROOT/cvsignore file. But if the user specified -I !,
+ the documented behavior is to not process said file. */
+ if (ign_inhibit_server)
+ {
+ send_arg ("-I");
+ send_arg ("!");
+ }
+ wrap_send ();
{
int i;
@@ -229,8 +263,7 @@ import (argc, argv)
client_import_setup (repository);
err = import_descend (message, argv[1], argc - 2, argv + 2);
client_import_done ();
- if (fprintf (to_server, "import\n") < 0)
- error (1, errno, "writing to server");
+ send_to_server ("import\012", 0);
err += get_responses_and_close ();
return err;
}
@@ -240,13 +273,18 @@ import (argc, argv)
* Make all newly created directories writable. Should really use a more
* sophisticated security mechanism here.
*/
- (void) umask (2);
+ (void) umask (cvsumask);
make_directories (repository);
/* Create the logfile that will be logged upon completion */
- if ((logfp = fopen (tmpnam (tmpfile), "w+")) == NULL)
+ tmpfile = cvs_temp_name ();
+ if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL)
error (1, errno, "cannot create temporary file `%s'", tmpfile);
- (void) unlink (tmpfile); /* to be sure it goes away */
+ /* On systems where we can unlink an open file, do so, so it will go
+ away no matter how we exit. FIXME-maybe: Should be checking for
+ errors but I'm not sure which error(s) we get if we are on a system
+ where one can't unlink open files. */
+ (void) CVS_UNLINK (tmpfile);
(void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
(void) fprintf (logfp, "Release Tags:\t");
for (i = 2; i < argc; i++)
@@ -259,24 +297,57 @@ import (argc, argv)
{
if (!really_quiet)
{
- (void) printf ("\n%d conflicts created by this import.\n",
- conflicts);
- (void) printf ("Use the following command to help the merge:\n\n");
- (void) printf ("\t%s checkout -j%s:yesterday -j%s %s\n\n",
- program_name, argv[1], argv[1], argv[0]);
+ char buf[20];
+ char *buf2;
+
+ cvs_output_tagged ("+importmergecmd", NULL);
+ cvs_output_tagged ("newline", NULL);
+ sprintf (buf, "%d", conflicts);
+ cvs_output_tagged ("conflicts", buf);
+ cvs_output_tagged ("text", " conflicts created by this import.");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text",
+ "Use the following command to help the merge:");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text", "\t");
+ cvs_output_tagged ("text", program_name);
+ if (CVSroot_cmdline != NULL)
+ {
+ cvs_output_tagged ("text", " -d ");
+ cvs_output_tagged ("text", CVSroot_cmdline);
+ }
+ cvs_output_tagged ("text", " checkout -j");
+ buf2 = xmalloc (strlen (argv[1]) + 20);
+ sprintf (buf2, "%s:yesterday", argv[1]);
+ cvs_output_tagged ("mergetag1", buf2);
+ free (buf2);
+ cvs_output_tagged ("text", " -j");
+ cvs_output_tagged ("mergetag2", argv[1]);
+ cvs_output_tagged ("text", " ");
+ cvs_output_tagged ("repository", argv[0]);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("-importmergecmd", NULL);
}
+ /* FIXME: I'm not sure whether we need to put this information
+ into the loginfo. If we do, then note that it does not
+ report any required -d option. There is no particularly
+ clean way to tell the server about the -d option used by
+ the client. */
(void) fprintf (logfp, "\n%d conflicts created by this import.\n",
conflicts);
(void) fprintf (logfp,
"Use the following command to help the merge:\n\n");
- (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
- program_name, argv[1], argv[1], argv[0]);
+ (void) fprintf (logfp, "\t%s checkout ", program_name);
+ (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
+ argv[1], argv[1], argv[0]);
}
else
{
if (!really_quiet)
- (void) printf ("\nNo conflicts created by this import\n\n");
+ cvs_output ("\nNo conflicts created by this import\n\n", 0);
(void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
}
@@ -288,25 +359,35 @@ import (argc, argv)
p->type = UPDATE;
p->delproc = update_delproc;
p->key = xstrdup ("- Imported sources");
- p->data = (char *) T_TITLE;
+ li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
+ li->type = T_TITLE;
+ li->tag = xstrdup (vbranch);
+ li->rev_old = li->rev_new = NULL;
+ p->data = (char *) li;
(void) addnode (ulist, p);
- Update_Logfile (repository, message, vbranch, logfp, ulist);
+ Update_Logfile (repository, message, logfp, ulist);
dellist (&ulist);
- (void) fclose (logfp);
+ if (fclose (logfp) < 0)
+ error (0, errno, "error closing %s", tmpfile);
/* Make sure the temporary file goes away, even on systems that don't let
you delete a file that's in use. */
- unlink (tmpfile);
+ if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
if (message)
free (message);
+ free (repository);
+ free (vbranch);
+ free (vhead);
return (err);
}
-/*
- * process all the files in ".", then descend into other directories.
- */
+/* Process all the files in ".", then descend into other directories.
+ Returns 0 for success, or >0 on error (in which case a message
+ will have been printed). */
static int
import_descend (message, vtag, targc, targv)
char *message;
@@ -323,28 +404,29 @@ import_descend (message, vtag, targc, targv)
ign_add_file (CVSDOTIGNORE, 1);
wrap_add_file (CVSDOTWRAPPER, 1);
- if ((dirp = opendir (".")) == NULL)
+ if ((dirp = CVS_OPENDIR (".")) == NULL)
{
+ error (0, errno, "cannot open directory");
err++;
}
else
{
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
- continue;
- if (ign_name (dp->d_name))
- {
+ goto one_more_time_boys;
#ifdef SERVER_SUPPORT
- /* CVS directories are created by server.c because it doesn't
- special-case import. So don't print a message about them.
- Do print a message about other ignored files (although
- most of these will get ignored on the client side). */
- if (server_active && strcmp (dp->d_name, CVSADM) == 0)
- continue;
+ /* CVS directories are created in the temp directory by
+ server.c because it doesn't special-case import. So
+ don't print a message about them, regardless of -I!. */
+ if (server_active && strcmp (dp->d_name, CVSADM) == 0)
+ goto one_more_time_boys;
#endif
+ if (ign_name (dp->d_name))
+ {
add_log ('I', dp->d_name);
- continue;
+ goto one_more_time_boys;
}
if (
@@ -356,7 +438,7 @@ import_descend (message, vtag, targc, targv)
#endif
&& !wrap_name_has (dp->d_name, WRAP_TOCVS)
)
- {
+ {
Node *n;
if (dirlist == NULL)
@@ -368,7 +450,7 @@ import_descend (message, vtag, targc, targv)
}
else if (
#ifdef DT_DIR
- dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
+ dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN &&
#endif
islink (dp->d_name))
{
@@ -380,18 +462,28 @@ import_descend (message, vtag, targc, targv)
#ifdef CLIENT_SUPPORT
if (client_active)
err += client_process_import_file (message, dp->d_name,
- vtag, targc, targv,
- repository);
+ vtag, targc, targv,
+ repository,
+ keyword_opt != NULL &&
+ keyword_opt[0] == 'b',
+ use_file_modtime);
else
#endif
err += process_import_file (message, dp->d_name,
vtag, targc, targv);
}
+ one_more_time_boys:
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory");
+ ++err;
}
(void) closedir (dirp);
}
- if (dirlist != NULL)
+ if (dirlist != NULL)
{
Node *head, *p;
@@ -418,28 +510,76 @@ process_import_file (message, vfile, vtag, targc, targv)
int targc;
char *targv[];
{
- char attic_name[PATH_MAX];
- char rcs[PATH_MAX];
+ char *rcs;
int inattic = 0;
+ rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT)
+ + 5);
(void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
if (!isfile (rcs))
{
+ char *attic_name;
+
+ attic_name = xmalloc (strlen (repository) + strlen (vfile) +
+ sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
(void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
vfile, RCSEXT);
if (!isfile (attic_name))
{
+ int retval;
+ char *free_opt = NULL;
+ char *our_opt = keyword_opt;
+ free (attic_name);
/*
* A new import source file; it doesn't exist as a ,v within the
* repository nor in the Attic -- create it anew.
*/
add_log ('N', vfile);
- return (add_rcs_file (message, rcs, vfile, vtag, targc, targv));
+
+#ifdef SERVER_SUPPORT
+ /* The most reliable information on whether the file is binary
+ is what the client told us. That is because if the client had
+ the wrong idea about binaryness, it corrupted the file, so
+ we might as well believe the client. */
+ if (server_active)
+ {
+ Node *node;
+ List *entries;
+
+ /* Reading all the entries for each file is fairly silly, and
+ probably slow. But I am too lazy at the moment to do
+ anything else. */
+ entries = Entries_Open (0, NULL);
+ node = findnode_fn (entries, vfile);
+ if (node != NULL)
+ {
+ Entnode *entdata = (Entnode *) node->data;
+ if (entdata->type == ENT_FILE)
+ {
+ assert (entdata->options[0] == '-'
+ && entdata->options[1] == 'k');
+ our_opt = xstrdup (entdata->options + 2);
+ free_opt = our_opt;
+ }
+ }
+ Entries_Close (entries);
+ }
+#endif
+
+ retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
+ vbranch, vtag, targc, targv,
+ NULL, 0, logfp);
+ if (free_opt != NULL)
+ free (free_opt);
+ free (rcs);
+ return retval;
}
+ free (attic_name);
inattic = 1;
}
+ free (rcs);
/*
* an rcs file exists. have to do things the official, slow, way.
*/
@@ -461,28 +601,23 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
{
Vers_TS *vers;
int letter;
- int ierrno;
- char *tmpdir;
char *tocvsPath;
-
- vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
-#ifdef DEATH_SUPPORT
+ struct file_info finfo;
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = vfile;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = repository;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+ vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL,
+ 1, 0);
if (vers->vn_rcs != NULL
&& !RCS_isdead(vers->srcfile, vers->vn_rcs))
-#else
- if (vers->vn_rcs != NULL)
-#endif
{
- char xtmpfile[PATH_MAX];
int different;
- int retcode = 0;
-
- tmpdir = getenv ("TMPDIR");
- if (tmpdir == NULL || tmpdir[0] == '\0')
- tmpdir = "/tmp";
-
- (void) sprintf (xtmpfile, "%s/cvs-imp%d", tmpdir, getpid());
/*
* The rcs file does have a revision on the vendor branch. Compare
@@ -493,33 +628,14 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
* This is to try to cut down the number of "C" conflict messages for
* locally modified import source files.
*/
-#ifdef HAVE_RCS5
- run_setup ("%s%s -q -f -r%s -p -ko", Rcsbin, RCS_CO, vers->vn_rcs);
-#else
- run_setup ("%s%s -q -f -r%s -p", Rcsbin, RCS_CO, vers->vn_rcs);
-#endif
- run_arg (vers->srcfile->path);
- if ((retcode = run_exec (RUN_TTY, xtmpfile, RUN_TTY,
- RUN_NORMAL|RUN_REALLY)) != 0)
- {
- ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
- vers->srcfile->path);
- error (0, retcode == -1 ? ierrno : 0,
- "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
- vers->srcfile->path);
- (void) unlink_file (xtmpfile);
- return (1);
- }
-
tocvsPath = wrap_tocvs_process_file (vfile);
- different = xcmp (xtmpfile, vfile);
+ /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
+ not NULL? */
+ different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, "-ko", vfile);
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
- (void) unlink_file (xtmpfile);
if (!different)
{
int retval = 0;
@@ -529,7 +645,7 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
* "U", signifying that the file has changed, but needs no
* attention, and we're done.
*/
- if (add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
+ if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
retval = 1;
add_log ('U', vfile);
freevers_ts (&vers);
@@ -539,8 +655,8 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
/* We may have failed to parse the RCS file; check just in case */
if (vers->srcfile == NULL ||
- add_rev (message, vers->srcfile->path, vfile, vers->vn_rcs) ||
- add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
+ add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
+ add_tags (vers->srcfile, vfile, vtag, targc, targv))
{
freevers_ts (&vers);
return (1);
@@ -566,13 +682,12 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
static int
add_rev (message, rcs, vfile, vers)
char *message;
- char *rcs;
+ RCSNode *rcs;
char *vfile;
char *vers;
{
int locked, status, ierrno;
char *tocvsPath;
- struct stat vfile_stat;
if (noexec)
return (0);
@@ -583,50 +698,39 @@ add_rev (message, rcs, vfile, vers)
/* Before RCS_lock existed, we were directing stdout, as well as
stderr, from the RCS command, to DEVNULL. I wouldn't guess that
was necessary, but I don't know for sure. */
- if (RCS_lock (rcs, vbranch, 1) != 0)
- {
- error (0, errno, "fork failed");
- return (1);
- }
+ /* Earlier versions of this function printed a `fork failed' error
+ when RCS_lock returned an error code. That's not appropriate
+ now that RCS_lock is librarified, but should the error text be
+ preserved? */
+ if (RCS_lock (rcs, vbranch, 1) != 0)
+ return 1;
locked = 1;
+ RCS_rewrite (rcs, NULL, NULL);
}
tocvsPath = wrap_tocvs_process_file (vfile);
- /* We used to deposit the revision with -r; RCS would delete the
- working file, but we'd keep a hard link to it, and rename it
- back after running RCS (ooh, atomicity). However, that
- strategy doesn't work on operating systems without hard links
- (like Windows NT). Instead, let's deposit it using -u, and
- restore its permission bits afterwards. This also means the
- file always exists under its own name. */
- if (! tocvsPath)
- stat (vfile, &vfile_stat);
-
- run_setup ("%s%s -q -f %s%s", Rcsbin, RCS_CI,
- (tocvsPath ? "-r" : "-u"),
- vbranch);
- run_args ("-m%s", make_message_rcslegal (message));
- if (use_file_modtime)
- run_arg ("-d");
- run_arg (tocvsPath == NULL ? vfile : tocvsPath);
- run_arg (rcs);
- status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
+ message, vbranch,
+ (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
+ | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
ierrno = errno;
- /* Restore the permissions on vfile. */
- if (! tocvsPath)
- chmod (vfile, vfile_stat.st_mode);
+ if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
+ error (0, errno, "cannot remove %s", tocvsPath);
if (status)
{
if (!noexec)
{
- fperror (logfp, 0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
- error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
+ fperror (logfp, 0, status == -1 ? ierrno : 0,
+ "ERROR: Check-in of %s failed", rcs->path);
+ error (0, status == -1 ? ierrno : 0,
+ "ERROR: Check-in of %s failed", rcs->path);
}
if (locked)
{
(void) RCS_unlock(rcs, vbranch, 0);
+ RCS_rewrite (rcs, NULL, NULL);
}
return (1);
}
@@ -641,7 +745,7 @@ add_rev (message, rcs, vfile, vers)
*/
static int
add_tags (rcs, vfile, vtag, targc, targv)
- char *rcs;
+ RCSNode *rcs;
char *vfile;
char *vtag;
int targc;
@@ -650,6 +754,7 @@ add_tags (rcs, vfile, vtag, targc, targv)
int i, ierrno;
Vers_TS *vers;
int retcode = 0;
+ struct file_info finfo;
if (noexec)
return (0);
@@ -657,23 +762,36 @@ add_tags (rcs, vfile, vtag, targc, targv)
if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
{
ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "ERROR: Failed to set tag %s in %s", vtag, rcs);
+ fperror (logfp, 0, retcode == -1 ? ierrno : 0,
+ "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
error (0, retcode == -1 ? ierrno : 0,
- "ERROR: Failed to set tag %s in %s", vtag, rcs);
+ "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
return (1);
}
- vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
+ RCS_rewrite (rcs, NULL, NULL);
+
+ memset (&finfo, 0, sizeof finfo);
+ finfo.file = vfile;
+ /* Not used, so don't worry about it. */
+ finfo.update_dir = NULL;
+ finfo.fullname = finfo.file;
+ finfo.repository = repository;
+ finfo.entries = NULL;
+ finfo.rcs = NULL;
+ vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
for (i = 0; i < targc; i++)
{
- if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) != 0)
+ if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
+ RCS_rewrite (rcs, NULL, NULL);
+ else
{
ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
+ fperror (logfp, 0, retcode == -1 ? ierrno : 0,
+ "WARNING: Couldn't add tag %s to %s", targv[i],
+ rcs->path);
error (0, retcode == -1 ? ierrno : 0,
- "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
+ "WARNING: Couldn't add tag %s to %s", targv[i],
+ rcs->path);
}
}
freevers_ts (&vers);
@@ -697,12 +815,17 @@ static const struct compair comtable[] =
* table is used to guess the proper comment leader from the working file's
* suffix during initial ci (see InitAdmin()). Comment leaders are needed for
* languages without multiline comments; for others they are optional.
+ *
+ * I believe that the comment leader is unused if you are using RCS 5.7, which
+ * decides what leader to use based on the text surrounding the $Log keyword
+ * rather than a specified comment leader.
*/
{"a", "-- "}, /* Ada */
{"ada", "-- "},
{"adb", "-- "},
{"asm", ";; "}, /* assembler (MS-DOS) */
{"ads", "-- "}, /* Ada */
+ {"bas", "' "}, /* Visual Basic code */
{"bat", ":: "}, /* batch (MS-DOS) */
{"body", "-- "}, /* Ada */
{"c", " * "}, /* C */
@@ -716,12 +839,14 @@ static const struct compair comtable[] =
{"cmf", "c "}, /* CM Fortran */
{"cs", " * "}, /* C* */
{"csh", "# "}, /* shell */
+ {"dlg", " * "}, /* MS Windows dialog file */
{"e", "# "}, /* efl */
{"epsf", "% "}, /* encapsulated postscript */
{"epsi", "% "}, /* encapsulated postscript */
{"el", "; "}, /* Emacs Lisp */
{"f", "c "}, /* Fortran */
{"for", "c "},
+ {"frm", "' "}, /* Visual Basic form */
{"h", " * "}, /* C-header */
{"hh", "// "}, /* C++ header */
{"hpp", "// "},
@@ -731,6 +856,7 @@ static const struct compair comtable[] =
* franzlisp) */
{"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
* VMS, etc) */
+ {"mak", "# "}, /* makefile, e.g. Visual C++ */
{"me", ".\\\" "}, /* me-macros t/nroff */
{"ml", "; "}, /* mocklisp */
{"mm", ".\\\" "}, /* mm-macros t/nroff */
@@ -752,17 +878,18 @@ static const struct compair comtable[] =
{"psw", "% "}, /* postscript wrap */
{"pswm", "% "}, /* postscript wrap */
{"r", "# "}, /* ratfor */
+ {"rc", " * "}, /* Microsoft Windows resource file */
{"red", "% "}, /* psl/rlisp */
-#ifdef sparc
+#ifdef __sparc__
{"s", "! "}, /* assembler */
#endif
-#ifdef mc68000
+#ifdef __mc68000__
{"s", "| "}, /* assembler */
#endif
-#ifdef pdp11
+#ifdef __pdp11__
{"s", "/ "}, /* assembler */
#endif
-#ifdef vax
+#ifdef __vax__
{"s", "# "}, /* assembler */
#endif
#ifdef __ksr__
@@ -776,9 +903,6 @@ static const struct compair comtable[] =
{"y", " * "}, /* yacc */
{"ye", " * "}, /* yacc-efl */
{"yr", " * "}, /* yacc-ratfor */
-#ifdef SYSTEM_COMMENT_TABLE
- SYSTEM_COMMENT_TABLE
-#endif
{"", "# "}, /* default for empty suffix */
{NULL, "# "} /* default for unknown suffix; */
/* must always be last */
@@ -789,9 +913,11 @@ get_comment (user)
char *user;
{
char *cp, *suffix;
- char suffix_path[PATH_MAX];
+ char *suffix_path;
int i;
+ char *retval;
+ suffix_path = xmalloc (strlen (user) + 5);
cp = strrchr (user, '.');
if (cp != NULL)
{
@@ -803,7 +929,7 @@ get_comment (user)
*/
(void) strcpy (suffix_path, cp);
for (cp = suffix_path; *cp; cp++)
- if (isupper (*cp))
+ if (isupper ((unsigned char) *cp))
*cp = tolower (*cp);
suffix = suffix_path;
}
@@ -811,56 +937,145 @@ get_comment (user)
suffix = ""; /* will use the default */
for (i = 0;; i++)
{
- if (comtable[i].suffix == NULL) /* default */
- return (comtable[i].comlead);
+ if (comtable[i].suffix == NULL)
+ {
+ /* Default. Note we'll always hit this case before we
+ ever return NULL. */
+ retval = comtable[i].comlead;
+ break;
+ }
if (strcmp (suffix, comtable[i].suffix) == 0)
- return (comtable[i].comlead);
+ {
+ retval = comtable[i].comlead;
+ break;
+ }
}
+ free (suffix_path);
+ return retval;
}
-static int
-add_rcs_file (message, rcs, user, vtag, targc, targv)
+/* Create a new RCS file from scratch.
+
+ This probably should be moved to rcs.c now that it is called from
+ places outside import.c.
+
+ Return value is 0 for success, or nonzero for failure (in which
+ case an error message will have already been printed). */
+int
+add_rcs_file (message, rcs, user, add_vhead, key_opt,
+ add_vbranch, vtag, targc, targv,
+ desctext, desclen, add_logfp)
+ /* Log message for the addition. Not used if add_vhead == NULL. */
char *message;
+ /* Filename of the RCS file to create. */
char *rcs;
+ /* Filename of the file to serve as the contents of the initial
+ revision. Even if add_vhead is NULL, we use this to determine
+ the modes to give the new RCS file. */
char *user;
+
+ /* Revision number of head that we are adding. Normally 1.1 but
+ could be another revision as long as ADD_VBRANCH is a branch
+ from it. If NULL, then just add an empty file without any
+ revisions (similar to the one created by "rcs -i"). */
+ char *add_vhead;
+
+ /* Keyword expansion mode, e.g., "b" for binary. NULL means the
+ default behavior. */
+ char *key_opt;
+
+ /* Vendor branch to import to, or NULL if none. If non-NULL, then
+ vtag should also be non-NULL. */
+ char *add_vbranch;
char *vtag;
int targc;
char *targv[];
+
+ /* If non-NULL, description for the file. If NULL, the description
+ will be empty. */
+ char *desctext;
+ size_t desclen;
+
+ /* Write errors to here as well as via error (), or NULL if we should
+ use only error (). */
+ FILE *add_logfp;
{
FILE *fprcs, *fpuser;
struct stat sb;
struct tm *ftm;
time_t now;
- char altdate1[50];
-#ifndef HAVE_RCS5
- char altdate2[50];
-#endif
- char *author, *buf;
+ char altdate1[MAXDATELEN];
+ char *author;
int i, ierrno, err = 0;
mode_t mode;
char *tocvsPath;
char *userfile;
+ char *local_opt = key_opt;
+ char *free_opt = NULL;
+ mode_t file_type;
if (noexec)
return (0);
-#ifdef LINES_CRLF_TERMINATED
- /* There exits a port of RCS to such a system that stores files with
- straight newlines. If we ever reach this point on such a system,
- we'll need to decide what to do with the open_file call below. */
- abort ();
-#endif
+ /* Note that as the code stands now, the -k option overrides any
+ settings in wrappers (whether CVSROOT/cvswrappers, -W, or
+ whatever). Some have suggested this should be the other way
+ around. As far as I know the documentation doesn't say one way
+ or the other. Before making a change of this sort, should think
+ about what is best, document it (in cvs.texinfo and NEWS), &c. */
+
+ if (local_opt == NULL)
+ {
+ if (wrap_name_has (user, WRAP_RCSOPTION))
+ {
+ local_opt = free_opt = wrap_rcsoption (user, 0);
+ }
+ }
+
tocvsPath = wrap_tocvs_process_file (user);
userfile = (tocvsPath == NULL ? user : tocvsPath);
- fpuser = fopen (userfile, "r");
- if (fpuser == NULL) {
- /* not fatal, continue import */
- fperror (logfp, 0, errno, "ERROR: cannot read file %s", userfile);
- error (0, errno, "ERROR: cannot read file %s", userfile);
- goto read_error;
+
+ /* Opening in text mode is probably never the right thing for the
+ server (because the protocol encodes text files in a fashion
+ which does not depend on what the client or server OS is, as
+ documented in cvsclient.texi), but as long as the server just
+ runs on unix it is a moot point. */
+
+ /* If PreservePermissions is set, then make sure that the file
+ is a plain file before trying to open it. Longstanding (although
+ often unpopular) CVS behavior has been to follow symlinks, so we
+ maintain that behavior if PreservePermissions is not on.
+
+ NOTE: this error message used to be `cannot fstat', but is now
+ `cannot lstat'. I don't see a way around this, since we must
+ stat the file before opening it. -twp */
+
+ if (CVS_LSTAT (userfile, &sb) < 0)
+ error (1, errno, "cannot lstat %s", user);
+ file_type = sb.st_mode & S_IFMT;
+
+ fpuser = NULL;
+ if (!preserve_perms || file_type == S_IFREG)
+ {
+ fpuser = CVS_FOPEN (userfile,
+ ((local_opt != NULL && strcmp (local_opt, "b") == 0)
+ ? "rb"
+ : "r")
+ );
+ if (fpuser == NULL)
+ {
+ /* not fatal, continue import */
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, errno,
+ "ERROR: cannot read file %s", userfile);
+ error (0, errno, "ERROR: cannot read file %s", userfile);
+ goto read_error;
+ }
}
- fprcs = fopen (rcs, "w+");
- if (fprcs == NULL) {
+
+ fprcs = CVS_FOPEN (rcs, "w+b");
+ if (fprcs == NULL)
+ {
ierrno = errno;
goto write_error_noclose;
}
@@ -868,156 +1083,325 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
/*
* putadmin()
*/
- if (fprintf (fprcs, "head %s;\n", vhead) < 0 ||
- fprintf (fprcs, "branch %s;\n", vbranch) < 0 ||
- fprintf (fprcs, "access ;\n") < 0 ||
+ if (add_vhead != NULL)
+ {
+ if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
+ goto write_error;
+ }
+ else
+ {
+ if (fprintf (fprcs, "head ;\012") < 0)
+ goto write_error;
+ }
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, "access ;\012") < 0 ||
fprintf (fprcs, "symbols ") < 0)
{
goto write_error;
}
- for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */
- if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) < 0)
+ for (i = targc - 1; i >= 0; i--)
+ {
+ /* RCS writes the symbols backwards */
+ assert (add_vbranch != NULL);
+ if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
+ goto write_error;
+ }
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
goto write_error;
+ }
+ if (fprintf (fprcs, ";\012") < 0)
+ goto write_error;
- if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) < 0 ||
- fprintf (fprcs, "locks ; strict;\n") < 0 ||
+ if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
/* XXX - make sure @@ processing works in the RCS file */
- fprintf (fprcs, "comment @%s@;\n", get_comment (user)) < 0)
+ fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
{
goto write_error;
}
- if (keyword_opt != NULL)
- if (fprintf (fprcs, "expand @%s@;\n", keyword_opt) < 0)
+ if (local_opt != NULL)
+ {
+ if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0)
{
- goto write_error;
+ goto write_error;
}
+ }
- if (fprintf (fprcs, "\n") < 0)
+ if (fprintf (fprcs, "\012") < 0)
goto write_error;
- /*
- * puttree()
- */
- if (fstat (fileno (fpuser), &sb) < 0)
- error (1, errno, "cannot fstat %s", user);
- if (use_file_modtime)
- now = sb.st_mtime;
- else
- (void) time (&now);
-#ifdef HAVE_RCS5
- ftm = gmtime (&now);
-#else
- ftm = localtime (&now);
+ /* Write the revision(s), with the date and author and so on
+ (that is "delta" rather than "deltatext" from rcsfile(5)). */
+ if (add_vhead != NULL)
+ {
+ if (use_file_modtime)
+ now = sb.st_mtime;
+ else
+ (void) time (&now);
+ ftm = gmtime (&now);
+ (void) sprintf (altdate1, DATEFORM,
+ ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+ ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+ ftm->tm_min, ftm->tm_sec);
+ author = getcaller ();
+
+ if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
+ altdate1, author) < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "branches") < 0)
+ goto write_error;
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, ";\012") < 0)
+ goto write_error;
+
+ if (fprintf (fprcs, "next ;\012") < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (preserve_perms)
+ {
+ if (file_type == S_IFLNK)
+ {
+ char *link = xreadlink (userfile);
+ if (fprintf (fprcs, "symlink\t@") < 0 ||
+ expand_at_signs (link, strlen (link), fprcs) < 0 ||
+ fprintf (fprcs, "@;\012") < 0)
+ goto write_error;
+ free (link);
+ }
+ else
+ {
+ if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "permissions\t%o;\012",
+ sb.st_mode & 07777) < 0)
+ goto write_error;
+ switch (file_type)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+ if (fprintf (fprcs, "special\t%s %lu;\012",
+ (file_type == S_IFCHR
+ ? "character"
+ : "block"),
+ (unsigned long) sb.st_rdev) < 0)
+ goto write_error;
+ break;
+ default:
+ error (0, 0,
+ "can't import %s: unknown kind of special file",
+ userfile);
+ }
+ }
+ }
#endif
- (void) sprintf (altdate1, DATEFORM,
- ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
- ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
- ftm->tm_min, ftm->tm_sec);
-#ifdef HAVE_RCS5
-#define altdate2 altdate1
-#else
- /*
- * If you don't have RCS V5 or later, you need to lie about the ci
- * time, since RCS V4 and earlier insist that the times differ.
- */
- now++;
- ftm = localtime (&now);
- (void) sprintf (altdate2, DATEFORM,
- ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
- ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
- ftm->tm_min, ftm->tm_sec);
+
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
+ altdate1, author) < 0 ||
+ fprintf (fprcs, "branches ;\012") < 0 ||
+ fprintf (fprcs, "next ;\012") < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (preserve_perms)
+ {
+ if (file_type == S_IFLNK)
+ {
+ char *link = xreadlink (userfile);
+ if (fprintf (fprcs, "symlink\t@") < 0 ||
+ expand_at_signs (link, strlen (link), fprcs) < 0 ||
+ fprintf (fprcs, "@;\012") < 0)
+ goto write_error;
+ free (link);
+ }
+ else
+ {
+ if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
+ fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
+ fprintf (fprcs, "permissions\t%o;\012",
+ sb.st_mode & 07777) < 0)
+ goto write_error;
+
+ switch (file_type)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+ if (fprintf (fprcs, "special\t%s %lu;\012",
+ (file_type == S_IFCHR
+ ? "character"
+ : "block"),
+ (unsigned long) sb.st_rdev) < 0)
+ goto write_error;
+ break;
+ default:
+ error (0, 0,
+ "cannot import %s: special file of unknown type",
+ userfile);
+ }
+ }
+ }
#endif
- author = getcaller ();
-
- if (fprintf (fprcs, "\n%s\n", vhead) < 0 ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
- altdate1, author) < 0 ||
- fprintf (fprcs, "branches %s.1;\n", vbranch) < 0 ||
- fprintf (fprcs, "next ;\n") < 0 ||
- fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
- altdate2, author) < 0 ||
- fprintf (fprcs, "branches ;\n") < 0 ||
- fprintf (fprcs, "next ;\n\n") < 0 ||
- /*
- * putdesc()
- */
- fprintf (fprcs, "\ndesc\n") < 0 ||
- fprintf (fprcs, "@@\n\n\n") < 0 ||
- /*
- * putdelta()
- */
- fprintf (fprcs, "\n%s\n", vhead) < 0 ||
- fprintf (fprcs, "log\n") < 0 ||
- fprintf (fprcs, "@Initial revision\n@\n") < 0 ||
- fprintf (fprcs, "text\n@") < 0)
- {
+
+ if (fprintf (fprcs, "\012") < 0)
+ goto write_error;
+ }
+ }
+
+ /* Now write the description (possibly empty). */
+ if (fprintf (fprcs, "\012desc\012") < 0 ||
+ fprintf (fprcs, "@") < 0)
goto write_error;
+ if (desctext != NULL)
+ {
+ /* The use of off_t not size_t for the second argument is very
+ strange, since we are dealing with something which definitely
+ fits in memory. */
+ if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
+ goto write_error;
}
+ if (fprintf (fprcs, "@\012\012\012") < 0)
+ goto write_error;
- if (sb.st_size > 0)
+ /* Now write the log messages and contents for the revision(s) (that
+ is, "deltatext" rather than "delta" from rcsfile(5)). */
+ if (add_vhead != NULL)
{
- off_t size;
+ if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
+ fprintf (fprcs, "log\012@") < 0)
+ goto write_error;
+ if (add_vbranch != NULL)
+ {
+ /* We are going to put the log message in the revision on the
+ branch. So putting it here too seems kind of redundant, I
+ guess (and that is what CVS has always done, anyway). */
+ if (fprintf (fprcs, "Initial revision\012") < 0)
+ goto write_error;
+ }
+ else
+ {
+ if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
+ goto write_error;
+ }
+ if (fprintf (fprcs, "@\012") < 0 ||
+ fprintf (fprcs, "text\012@") < 0)
+ {
+ goto write_error;
+ }
- size = sb.st_size;
- buf = xmalloc ((int) size);
- if (fread (buf, (int) size, 1, fpuser) != 1)
- error (1, errno, "cannot read file %s for copying", user);
- if (expand_at_signs (buf, size, fprcs) < 0)
+ /* Now copy over the contents of the file, expanding at signs.
+ If preserve_perms is set, do this only for regular files. */
+ if (!preserve_perms || file_type == S_IFREG)
{
- free (buf);
+ char buf[8192];
+ unsigned int len;
+
+ while (1)
+ {
+ len = fread (buf, 1, sizeof buf, fpuser);
+ if (len == 0)
+ {
+ if (ferror (fpuser))
+ error (1, errno, "cannot read file %s for copying",
+ user);
+ break;
+ }
+ if (expand_at_signs (buf, len, fprcs) < 0)
+ goto write_error;
+ }
+ }
+ if (fprintf (fprcs, "@\012\012") < 0)
goto write_error;
+ if (add_vbranch != NULL)
+ {
+ if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
+ fprintf (fprcs, "log\012@") < 0 ||
+ expand_at_signs (message,
+ (off_t) strlen (message), fprcs) < 0 ||
+ fprintf (fprcs, "@\012text\012") < 0 ||
+ fprintf (fprcs, "@@\012") < 0)
+ goto write_error;
}
- free (buf);
- }
- if (fprintf (fprcs, "@\n\n") < 0 ||
- fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
- fprintf (fprcs, "log\n@") < 0 ||
- expand_at_signs (message, (off_t) strlen (message), fprcs) < 0 ||
- fprintf (fprcs, "@\ntext\n") < 0 ||
- fprintf (fprcs, "@@\n") < 0)
- {
- goto write_error;
}
+
if (fclose (fprcs) == EOF)
{
ierrno = errno;
goto write_error_noclose;
}
- (void) fclose (fpuser);
+ /* Close fpuser only if we opened it to begin with. */
+ if (fpuser != NULL)
+ {
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ }
/*
- * Fix the modes on the RCS files. They must maintain the same modes as
- * the original user file, except that all write permissions must be
+ * Fix the modes on the RCS files. The user modes of the original
+ * user file are propagated to the group and other modes as allowed
+ * by the repository umask, except that all write permissions are
* turned off.
*/
- mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
+ mode = (sb.st_mode |
+ (sb.st_mode & S_IRWXU) >> 3 |
+ (sb.st_mode & S_IRWXU) >> 6) &
+ ~cvsumask &
+ ~(S_IWRITE | S_IWGRP | S_IWOTH);
if (chmod (rcs, mode) < 0)
{
ierrno = errno;
- fperror (logfp, 0, ierrno,
- "WARNING: cannot change mode of file %s", rcs);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
err++;
}
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
+ if (free_opt != NULL)
+ free (free_opt);
return (err);
write_error:
ierrno = errno;
- (void) fclose (fprcs);
+ if (fclose (fprcs) < 0)
+ error (0, errno, "cannot close %s", rcs);
write_error_noclose:
- (void) fclose (fpuser);
- fperror (logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
error (0, ierrno, "ERROR: cannot write file %s", rcs);
if (ierrno == ENOSPC)
{
- (void) unlink (rcs);
- fperror (logfp, 0, 0, "ERROR: out of space - aborting");
+ if (CVS_UNLINK (rcs) < 0)
+ error (0, errno, "cannot remove %s", rcs);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, 0, "ERROR: out of space - aborting");
error (1, 0, "ERROR: out of space - aborting");
}
read_error:
@@ -1025,6 +1409,9 @@ read_error:
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
+ if (free_opt != NULL)
+ free (free_opt);
+
return (err + 1);
}
@@ -1033,25 +1420,33 @@ read_error:
* signs. If an error occurs, return a negative value and set errno
* to indicate the error. If not, return a nonnegative value.
*/
-static int
+int
expand_at_signs (buf, size, fp)
char *buf;
off_t size;
FILE *fp;
{
- char *cp, *end;
+ register char *cp, *next;
- for (cp = buf, end = buf + size; cp < end; cp++)
+ cp = buf;
+ while ((next = memchr (cp, '@', size)) != NULL)
{
- if (*cp == '@')
- {
- if (putc ('@', fp) == EOF)
- return EOF;
- }
- if (putc (*cp, fp) == EOF)
- return (EOF);
+ int len;
+
+ ++next;
+ len = next - cp;
+ if (fwrite (cp, 1, len, fp) != len)
+ return EOF;
+ if (putc ('@', fp) == EOF)
+ return EOF;
+ cp = next;
+ size -= len;
}
- return (1);
+
+ if (fwrite (cp, 1, size, fp) != size)
+ return EOF;
+
+ return 1;
}
/*
@@ -1064,12 +1459,22 @@ add_log (ch, fname)
{
if (!really_quiet) /* write to terminal */
{
+ char buf[2];
+ buf[0] = ch;
+ buf[1] = ' ';
+ cvs_output (buf, 2);
if (repos_len)
- (void) printf ("%c %s/%s\n", ch, repository + repos_len + 1, fname);
- else if (repository[0])
- (void) printf ("%c %s/%s\n", ch, repository, fname);
- else
- (void) printf ("%c %s\n", ch, fname);
+ {
+ cvs_output (repository + repos_len + 1, 0);
+ cvs_output ("/", 1);
+ }
+ else if (repository[0] != '\0')
+ {
+ cvs_output (repository, 0);
+ cvs_output ("/", 1);
+ }
+ cvs_output (fname, 0);
+ cvs_output ("\n", 1);
}
if (repos_len) /* write to logfile */
@@ -1099,6 +1504,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
struct saved_cwd cwd;
char *cp;
int ierrno, err;
+ char *rcs = NULL;
if (islink (dir))
return (0);
@@ -1107,28 +1513,32 @@ import_descend_dir (message, dir, vtag, targc, targv)
fperror (logfp, 0, 0, "ERROR: cannot get working directory");
return (1);
}
+
+ /* Concatenate DIR to the end of REPOSITORY. */
if (repository[0] == '\0')
- (void) strcpy (repository, dir);
+ {
+ char *new = xstrdup (dir);
+ free (repository);
+ repository = new;
+ }
else
{
- (void) strcat (repository, "/");
- (void) strcat (repository, dir);
+ char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
+ strcpy (new, repository);
+ (void) strcat (new, "/");
+ (void) strcat (new, dir);
+ free (repository);
+ repository = new;
}
+
#ifdef CLIENT_SUPPORT
if (!quiet && !client_active)
#else
if (!quiet)
#endif
-#ifdef SERVER_SUPPORT
- /* Needs to go on stdout, not stderr, to avoid being interspersed
- with the add_log messages. */
- printf ("%s %s: Importing %s\n",
- program_name, command_name, repository);
-#else
error (0, 0, "Importing %s", repository);
-#endif
- if (chdir (dir) < 0)
+ if ( CVS_CHDIR (dir) < 0)
{
ierrno = errno;
fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
@@ -1142,9 +1552,12 @@ import_descend_dir (message, dir, vtag, targc, targv)
if (!isdir (repository))
#endif
{
- if (isfile (repository))
+ rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
+ (void) sprintf (rcs, "%s%s", repository, RCSEXT);
+ if (isfile (repository) || isfile(rcs))
{
- fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!",
+ fperror (logfp, 0, 0,
+ "ERROR: %s is a file, should be a directory!",
repository);
error (0, 0, "ERROR: %s is a file, should be a directory!",
repository);
@@ -1164,12 +1577,14 @@ import_descend_dir (message, dir, vtag, targc, targv)
}
err = import_descend (message, vtag, targc, targv);
out:
+ if (rcs != NULL)
+ free (rcs);
if ((cp = strrchr (repository, '/')) != NULL)
*cp = '\0';
else
repository[0] = '\0';
if (restore_cwd (&cwd, NULL))
- exit (1);
+ error_exit ();
free_cwd (&cwd);
return (err);
}