diff options
| author | David E. O'Brien <obrien@FreeBSD.org> | 2008-07-28 16:52:28 +0000 |
|---|---|---|
| committer | David E. O'Brien <obrien@FreeBSD.org> | 2008-07-28 16:52:28 +0000 |
| commit | 7cd98dc67430e6bf5ff17569ccf508bb0d423b6c (patch) | |
| tree | 391480898e23fe9274aee62b7154da7be9b02e51 /contrib/cvs/src/client.c | |
| parent | c7ca105239310a45435e9a99cda3c5483976ae3d (diff) | |
Notes
Diffstat (limited to 'contrib/cvs/src/client.c')
| -rw-r--r-- | contrib/cvs/src/client.c | 267 |
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]); } |
