summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/client.c
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2008-07-28 16:52:28 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2008-07-28 16:52:28 +0000
commit7cd98dc67430e6bf5ff17569ccf508bb0d423b6c (patch)
tree391480898e23fe9274aee62b7154da7be9b02e51 /contrib/cvs/src/client.c
parentc7ca105239310a45435e9a99cda3c5483976ae3d (diff)
Notes
Diffstat (limited to 'contrib/cvs/src/client.c')
-rw-r--r--contrib/cvs/src/client.c267
1 files changed, 131 insertions, 136 deletions
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index aae404a58488..1c8a5d0971e6 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -164,17 +164,22 @@ is_arg_a_parent_or_listed_dir (n, d)
void *d;
{
char *directory = n->key; /* name of the dir sent to server */
- char *this_argv_elem = (char *) d; /* this argv element */
+ char *this_argv_elem = xstrdup (d); /* this argv element */
+ int retval;
/* Say we should send this argument if the argument matches the
beginning of a directory name sent to the server. This way,
the server will know to start at the top of that directory
hierarchy and descend. */
+ strip_trailing_slashes (this_argv_elem);
if (strncmp (directory, this_argv_elem, strlen (this_argv_elem)) == 0)
- return 1;
+ retval = 1;
+ else
+ retval = 0;
- return 0;
+ free (this_argv_elem);
+ return retval;
}
static int arg_should_not_be_sent_to_server PROTO((char *));
@@ -225,7 +230,8 @@ arg_should_not_be_sent_to_server (arg)
/* Try to decide whether we should send arg to the server by
checking the contents of the corresponding CVSADM directory. */
{
- char *t, *this_root;
+ char *t, *root_string;
+ cvsroot_t *this_root = NULL;
/* Calculate "dirname arg" */
for (t = arg + strlen (arg) - 1; t >= arg; t--)
@@ -255,25 +261,32 @@ arg_should_not_be_sent_to_server (arg)
/* Since we didn't find it in the list, check the CVSADM
files on disk. */
this_root = Name_Root (arg, (char *) NULL);
+ root_string = this_root->original;
*t = c;
}
else
{
/* We're at the beginning of the string. Look at the
CVSADM files in cwd. */
- this_root = (CVSroot_cmdline ? xstrdup(CVSroot_cmdline)
- : Name_Root ((char *) NULL, (char *) NULL));
+ if (CVSroot_cmdline)
+ root_string = CVSroot_cmdline;
+ else
+ {
+ this_root = Name_Root ((char *) NULL, (char *) NULL);
+ root_string = this_root->original;
+ }
}
/* Now check the value for root. */
- if (CVSroot_cmdline == NULL && this_root && current_parsed_root
- && (strcmp (this_root, current_parsed_root->original) != 0))
+ if (CVSroot_cmdline == NULL &&
+ root_string && current_parsed_root
+ && (strcmp (root_string, current_parsed_root->original) != 0))
{
/* Don't send this, since the CVSROOTs don't match. */
- free (this_root);
+ if (this_root) free_cvsroot_t (this_root);
return 1;
}
- free (this_root);
+ if (this_root) free_cvsroot_t (this_root);
}
/* OK, let's send it. */
@@ -890,12 +903,6 @@ read_line (resultp)
#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
/*
- * Zero if compression isn't supported or requested; non-zero to indicate
- * a compression level to request from gzip.
- */
-int gzip_level;
-
-/*
* Level of compression to use when running gzip on a single file.
*/
int file_gzip_level;
@@ -1117,6 +1124,8 @@ call_in_directory (pathname, func, data)
int reposdirname_absolute;
int newdir = 0;
+ assert (pathname);
+
reposname = NULL;
read_line (&reposname);
assert (reposname != NULL);
@@ -1198,44 +1207,6 @@ call_in_directory (pathname, func, data)
if (CVS_CHDIR (toplevel_wd) < 0)
error (1, errno, "could not chdir to %s", toplevel_wd);
- /* Create the CVS directory at the top level if needed. The
- isdir seems like an unneeded system call, but it *does*
- need to be called both if the CVS_CHDIR below succeeds
- (e.g. "cvs co .") or if it fails (e.g. basicb-1a in
- testsuite). We only need to do this for the "." case,
- since the server takes care of forcing this directory to be
- created in all other cases. If we don't create CVSADM
- here, the call to Entries_Open below will fail. FIXME:
- perhaps this means that we should change our algorithm
- below that calls Create_Admin instead of having this code
- here? */
- if (/* I think the reposdirname_absolute case has to do with
- things like "cvs update /foo/bar". In any event, the
- code below which tries to put toplevel_repos into
- CVS/Repository is almost surely unsuited to
- the reposdirname_absolute case. */
- !reposdirname_absolute
- && (strcmp (dir_name, ".") == 0)
- && ! isdir (CVSADM))
- {
- char *repo;
- char *r;
-
- newdir = 1;
-
- repo = xmalloc (strlen (toplevel_repos)
- + 10);
- strcpy (repo, toplevel_repos);
- r = repo + strlen (repo);
- if (r[-1] != '.' || r[-2] != '/')
- strcpy (r, "/.");
-
- Create_Admin (".", ".", repo, (char *) NULL,
- (char *) NULL, 0, 1, 1);
-
- free (repo);
- }
-
if (CVS_CHDIR (dir_name) < 0)
{
char *dir;
@@ -1496,7 +1467,44 @@ handle_copy_file (args, len)
{
call_in_directory (args, copy_a_file, (char *)NULL);
}
-
+
+
+
+/* Attempt to read a file size from a string. Accepts base 8 (0N), base 16
+ * (0xN), or base 10. Exits on error.
+ *
+ * RETURNS
+ * The file size, in a size_t.
+ *
+ * FATAL ERRORS
+ * 1. As strtoul().
+ * 2. If the number read exceeds SIZE_MAX.
+ */
+static size_t
+strto_file_size (const char *s)
+{
+ unsigned long tmp;
+ char *endptr;
+
+ /* Read it. */
+ errno = 0;
+ tmp = strtoul (s, &endptr, 0);
+
+ /* Check for errors. */
+ if (errno || endptr == s)
+ error (1, errno, "Server sent invalid file size `%s'", s);
+ if (*endptr != '\0')
+ error (1, 0,
+ "Server sent trailing characters in file size `%s'",
+ endptr);
+ if (tmp > SIZE_MAX)
+ error (1, 0, "Server sent file size exceeding client max.");
+
+ /* Return it. */
+ return (size_t)tmp;
+}
+
+
static void read_counted_file PROTO ((char *, char *));
@@ -1529,9 +1537,7 @@ read_counted_file (filename, fullname)
if (size_string[0] == 'z')
error (1, 0, "\
protocol error: compressed files not supported for that operation");
- /* FIXME: should be doing more error checking, probably. Like using
- strtoul and making sure we used up the whole line. */
- size = atoi (size_string);
+ size = strto_file_size (size_string);
free (size_string);
/* A more sophisticated implementation would use only a limited amount
@@ -1813,11 +1819,12 @@ update_entries (data_arg, ent_list, short_pathname, filename)
{
char *size_string;
char *mode_string;
- int size;
+ size_t size;
char *buf;
char *temp_filename;
int use_gzip;
int patch_failed;
+ char *s;
read_line (&mode_string);
@@ -1825,13 +1832,14 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (size_string[0] == 'z')
{
use_gzip = 1;
- size = atoi (size_string+1);
+ s = size_string + 1;
}
else
{
use_gzip = 0;
- size = atoi (size_string);
+ s = size_string;
}
+ size = strto_file_size (s);
free (size_string);
/* Note that checking this separately from writing the file is
@@ -1932,7 +1940,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
#ifdef USE_VMS_FILENAMES
/* A VMS rename of "blah.dat" to "foo" to implies a
destination of "foo.dat" which is unfortinate for CVS */
- sprintf (temp_filename, "%s_new_", filename);
+ sprintf (temp_filename, "%s_new_", filename);
#else
#ifdef _POSIX_NO_TRUNC
sprintf (temp_filename, ".new.%.9s", filename);
@@ -1985,6 +1993,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
entirely possible that future files will not have
the same problem. */
error (0, errno, "cannot write %s", short_pathname);
+ free (temp_filename);
+ free (buf);
goto discard_file_and_return;
}
@@ -2778,7 +2788,8 @@ send_repository (dir, repos, update_dir)
send_to_server (repos, 0);
send_to_server ("\012", 1);
- if (supported_request ("Static-directory"))
+ if (strcmp (cvs_cmd_name, "import")
+ && supported_request ("Static-directory"))
{
adm_name[0] = '\0';
if (dir[0] != '\0')
@@ -2792,7 +2803,8 @@ send_repository (dir, repos, update_dir)
send_to_server ("Static-directory\012", 0);
}
}
- if (supported_request ("Sticky"))
+ if (strcmp (cvs_cmd_name, "import")
+ && supported_request ("Sticky"))
{
FILE *f;
if (dir[0] == '\0')
@@ -2841,7 +2853,10 @@ send_a_repository (dir, repository, update_dir_in)
const char *repository;
const char *update_dir_in;
{
- char *update_dir = xstrdup (update_dir_in);
+ char *update_dir;
+
+ assert (update_dir_in);
+ update_dir = xstrdup (update_dir_in);
if (toplevel_repos == NULL && repository != NULL)
{
@@ -3101,7 +3116,7 @@ handle_mbinary (args, len)
/* Get the size. */
read_line (&size_string);
- size = atoi (size_string);
+ size = strto_file_size (size_string);
free (size_string);
/* OK, now get all the data. The algorithm here is that we read
@@ -3250,7 +3265,7 @@ handle_mt (args, len)
else if (importmergecmd.seen)
{
if (strcmp (tag, "conflicts") == 0)
- importmergecmd.conflicts = atoi (text);
+ importmergecmd.conflicts = text ? atoi (text) : -1;
else if (strcmp (tag, "mergetag1") == 0)
importmergecmd.mergetag1 = xstrdup (text);
else if (strcmp (tag, "mergetag2") == 0)
@@ -3832,7 +3847,7 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
int do_gssapi;
struct hostent *hostinfo;
{
- char *username; /* the username we use to connect */
+ char *username = ""; /* the username we use to connect */
char no_passwd = 0; /* gets set if no password found */
/* FIXME!!!!!!!!!!!!!!!!!!
@@ -3916,8 +3931,8 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
send_to_server(end, 0);
send_to_server("\012", 1);
- /* Paranoia. */
- memset (password, 0, strlen (password));
+ free_cvs_password (password);
+ password = NULL;
# else /* ! AUTH_CLIENT_SUPPORT */
error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication");
# endif /* AUTH_CLIENT_SUPPORT */
@@ -4032,7 +4047,7 @@ connect_to_forked_server (to_server, from_server)
fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]);
}
- child_pid = piped_child (command, &tofd, &fromfd);
+ child_pid = piped_child (command, &tofd, &fromfd, 0);
if (child_pid < 0)
error (1, 0, "could not fork server process");
@@ -4236,7 +4251,8 @@ connect_to_gserver (root, sock, hostinfo)
if (need > sizeof buf)
{
- int got;
+ ssize_t got;
+ size_t total;
/* This usually means that the server sent us an error
message. Read it byte by byte and print it out.
@@ -4245,13 +4261,19 @@ connect_to_gserver (root, sock, hostinfo)
want to do this to work with older servers. */
buf[0] = cbuf[0];
buf[1] = cbuf[1];
- got = recv (sock, buf + 2, sizeof buf - 2, 0);
- if (got < 0)
- error (1, 0, "recv() from server %s: %s",
- root->hostname, SOCK_STRERROR (SOCK_ERRNO));
- buf[got + 2] = '\0';
- if (buf[got + 1] == '\n')
- buf[got + 1] = '\0';
+ total = 2;
+ while (got = recv (sock, buf + total, sizeof buf - total, 0))
+ {
+ if (got < 0)
+ error (1, 0, "recv() from server %s: %s",
+ root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+ total += got;
+ if (strrchr (buf + total - got, '\n'))
+ break;
+ }
+ buf[total] = '\0';
+ if (buf[total - 1] == '\n')
+ buf[total - 1] = '\0';
error (1, 0, "error from server %s: %s", root->hostname,
buf);
}
@@ -4332,6 +4354,7 @@ start_server ()
#endif /* HAVE_GSSAPI */
case ext_method:
+ case extssh_method:
#ifdef NO_EXT_METHOD
error (0, 0, ":ext: method not supported by this port of CVS");
error (1, 0, "try :server: instead");
@@ -4708,35 +4731,20 @@ start_rsh_server (root, to_server, from_server)
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
invoke another rsh on a proxy machine. */
- char *cvs_rsh = getenv ("CVS_RSH");
+ char *env_cvs_rsh = getenv ("CVS_RSH");
+ char *env_cvs_ssh = getenv ("CVS_SSH");
+ char *cvs_rsh;
char *cvs_server = getenv ("CVS_SERVER");
int i = 0;
/* This needs to fit "rsh", "-b", "-l", "USER", "host",
"cmd (w/ args)", and NULL. We leave some room to grow. */
char *rsh_argv[10];
- if (!cvs_rsh)
- /* People sometimes suggest or assume that this should default
- to "remsh" on systems like HPUX in which that is the
- system-supplied name for the rsh program. However, that
- causes various problems (keep in mind that systems such as
- HPUX might have non-system-supplied versions of "rsh", like
- a Kerberized one, which one might want to use). If we
- based the name on what is found in the PATH of the person
- who runs configure, that would make it harder to
- consistently produce the same result in the face of
- different people producing binary distributions. If we
- based it on "remsh" always being the default for HPUX
- (e.g. based on uname), that might be slightly better but
- would require us to keep track of what the defaults are for
- each system type, and probably would cope poorly if the
- existence of remsh or rsh varies from OS version to OS
- version. Therefore, it seems best to have the default
- remain "rsh", and tell HPUX users to specify remsh, for
- example in CVS_RSH or other such mechanisms to be devised,
- if that is what they want (the manual already tells them
- that). */
- cvs_rsh = "ssh";
+ if (root->method == extssh_method)
+ cvs_rsh = env_cvs_ssh ? env_cvs_ssh : SSH_DFLT;
+ else
+ cvs_rsh = env_cvs_rsh ? env_cvs_rsh : RSH_DFLT;
+
if (!cvs_server)
cvs_server = "cvs";
@@ -4790,14 +4798,19 @@ start_rsh_server (root, to_server, from_server)
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
invoke another rsh on a proxy machine. */
- char *cvs_rsh = getenv ("CVS_RSH");
+ char *env_cvs_rsh = getenv ("CVS_RSH");
+ char *env_cvs_ssh = getenv ("CVS_SSH");
+ char *cvs_rsh;
char *cvs_server = getenv ("CVS_SERVER");
char *command;
int tofd, fromfd;
int child_pid;
- if (!cvs_rsh)
- cvs_rsh = "ssh";
+ if (root->method == extssh_method)
+ cvs_rsh = env_cvs_ssh ? env_cvs_ssh : SSH_DFLT;
+ else
+ cvs_rsh = env_cvs_rsh ? env_cvs_rsh : RSH_DFLT;
+
if (!cvs_server)
cvs_server = "cvs";
@@ -4841,7 +4854,7 @@ start_rsh_server (root, to_server, from_server)
fprintf (stderr, "%s ", argv[i]);
putc ('\n', stderr);
}
- child_pid = piped_child (argv, &tofd, &fromfd);
+ child_pid = piped_child (argv, &tofd, &fromfd, 1);
if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
@@ -4860,10 +4873,10 @@ start_rsh_server (root, to_server, from_server)
/* Send an argument STRING. */
void
send_arg (string)
- char *string;
+ const char *string;
{
char buf[1];
- char *p = string;
+ const char *p = string;
send_to_server ("Argument ", 0);
@@ -5155,7 +5168,10 @@ warning: ignoring -k options due to server limitations");
}
else if (vers->ts_rcs == NULL
|| args->force
- || strcmp (vers->ts_user, vers->ts_rcs) != 0
+ || strcmp (vers->ts_conflict
+ && supported_request ("Empty-conflicts")
+ ? vers->ts_conflict : vers->ts_rcs, vers->ts_user)
+ || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff"))
|| (vers->vn_user && *vers->vn_user == '0'))
{
if (args->no_contents
@@ -5362,36 +5378,15 @@ send_dirleave_proc (callerdat, dir, err, update_dir, entries)
}
/*
- * Send each option in a string to the server, one by one.
- * This assumes that the options are separated by spaces, for example
- * STRING might be "--foo -C5 -y".
+ * Send each option in an array to the server, one by one.
+ * argv might be "--foo=bar", "-C", "5", "-y".
*/
-
void
-send_option_string (string)
- char *string;
+send_options (int argc, char *const *argv)
{
- char *copy;
- char *p;
-
- copy = xstrdup (string);
- p = copy;
- while (1)
- {
- char *s;
- char l;
-
- for (s = p; *s != ' ' && *s != '\0'; s++)
- ;
- l = *s;
- *s = '\0';
- if (s != p)
- send_arg (p);
- if (l == '\0')
- break;
- p = s + 1;
- }
- free (copy);
+ int i;
+ for (i = 0; i < argc; i++)
+ send_arg (argv[i]);
}