summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2000-10-02 06:43:58 +0000
committerpeter <peter@FreeBSD.org>2000-10-02 06:43:58 +0000
commita152a7ef82d848279559ecbca83c547e47aa8c9d (patch)
treeccd783be8562c7bf052885106d7a3efd32f7be0c /contrib/cvs/src
parente0aa09eb3434450a9aec24a6f4b2694077991e45 (diff)
downloadFreeBSD-src-a152a7ef82d848279559ecbca83c547e47aa8c9d.zip
FreeBSD-src-a152a7ef82d848279559ecbca83c547e47aa8c9d.tar.gz
Merge changes from 1.10.7 -> 1.11 into mainline. Note that the old
anoncvs no-password hack is gone and is replaced by the official version.
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r--contrib/cvs/src/client.c167
-rw-r--r--contrib/cvs/src/commit.c179
-rw-r--r--contrib/cvs/src/cvs.h16
-rw-r--r--contrib/cvs/src/filesubr.c9
-rw-r--r--contrib/cvs/src/import.c78
-rw-r--r--contrib/cvs/src/lock.c12
-rw-r--r--contrib/cvs/src/login.c64
-rw-r--r--contrib/cvs/src/logmsg.c16
-rw-r--r--contrib/cvs/src/main.c94
-rw-r--r--contrib/cvs/src/mkmodules.c38
-rw-r--r--contrib/cvs/src/rcs.c851
-rw-r--r--contrib/cvs/src/rcs.h8
-rw-r--r--contrib/cvs/src/recurse.c13
-rw-r--r--contrib/cvs/src/server.c532
-rw-r--r--contrib/cvs/src/update.c252
15 files changed, 1213 insertions, 1116 deletions
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index eafe916..3119613 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -1,3 +1,5 @@
+/* JT thinks BeOS is worth the trouble. */
+
/* CVS client-related stuff.
This program is free software; you can redistribute it and/or modify
@@ -64,7 +66,6 @@ extern char *strerror ();
#if HAVE_KERBEROS
#define CVS_PORT 1999
-#if HAVE_KERBEROS
#include <krb.h>
extern char *krb_realmofhost ();
@@ -78,8 +79,6 @@ static Key_schedule sched;
#endif /* HAVE_KERBEROS */
-#endif /* HAVE_KERBEROS */
-
#ifdef HAVE_GSSAPI
#ifdef HAVE_GSSAPI_H
@@ -1119,7 +1118,7 @@ call_in_directory (pathname, func, data)
strcpy (r, "/.");
Create_Admin (".", ".", repo, (char *) NULL,
- (char *) NULL, 0, 1);
+ (char *) NULL, 0, 1, 1);
free (repo);
}
@@ -1256,7 +1255,7 @@ warning: server is not creating directories one at a time");
strcpy (r, reposdirname);
Create_Admin (dir, dir, repo,
- (char *)NULL, (char *)NULL, 0, 0);
+ (char *)NULL, (char *)NULL, 0, 0, 1);
free (repo);
b = strrchr (dir, '/');
@@ -1764,6 +1763,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
}
free (mode_string);
+ free (scratch_entries);
free (entries_line);
/* The Mode, Mod-time, and Checksum responses should not carry
@@ -1851,7 +1851,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (use_gzip)
{
- if (gunzip_and_write (fd, short_pathname, buf, size))
+ if (gunzip_and_write (fd, short_pathname,
+ (unsigned char *) buf, size))
error (1, 0, "aborting due to compression error");
}
else if (write (fd, buf, size) != size)
@@ -2029,6 +2030,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
free (mode_string);
free (buf);
+ free (scratch_entries);
+ free (entries_line);
return;
}
@@ -2127,8 +2130,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (file_timestamp)
free (file_timestamp);
- free (scratch_entries);
}
+ free (scratch_entries);
free (entries_line);
}
@@ -2494,7 +2497,11 @@ handle_set_checkin_prog (args, len)
{
char *prog;
struct save_prog *p;
+
read_line (&prog);
+ if (strcmp (command_name, "export") == 0)
+ return;
+
p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
p->next = checkin_progs;
p->dir = xstrdup (args);
@@ -2509,7 +2516,11 @@ handle_set_update_prog (args, len)
{
char *prog;
struct save_prog *p;
+
read_line (&prog);
+ if (strcmp (command_name, "export") == 0)
+ return;
+
p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
p->next = update_progs;
p->dir = xstrdup (args);
@@ -2687,7 +2698,7 @@ send_repository (dir, repos, update_dir)
{
Node *n;
n = getnode ();
- n->type = UNKNOWN;
+ n->type = NT_UNKNOWN;
n->key = xstrdup (update_dir);
n->data = NULL;
@@ -3598,19 +3609,15 @@ get_responses_and_close ()
&& waitpid (rsh_pid, (int *) 0, 0) == -1)
error (1, errno, "waiting for process %d", rsh_pid);
+ buf_free (to_server);
+ buf_free (from_server);
server_started = 0;
- /* see if we need to sleep before returning */
+ /* see if we need to sleep before returning to avoid time-stamp races */
if (last_register_time)
{
- time_t now;
-
- for (;;)
- {
- (void) time (&now);
- if (now != last_register_time) break;
- sleep (1); /* to avoid time-stamp races */
- }
+ while (time ((time_t *) NULL) == last_register_time)
+ sleep (1);
}
return errs;
@@ -3778,6 +3785,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
int port_number;
struct sockaddr_in client_sai;
struct hostent *hostinfo;
+ char no_passwd = 0; /* gets set if no password found */
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
@@ -3822,6 +3830,14 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
/* Get the password, probably from ~/.cvspass. */
password = get_cvs_password ();
+
+ /* Send the empty string by default. This is so anonymous CVS
+ access doesn't require client to have done "cvs login". */
+ if (password == NULL)
+ {
+ no_passwd = 1;
+ password = scramble ("");
+ }
/* Announce that we're starting the authorization protocol. */
if (send (sock, begin, strlen (begin), 0) < 0)
@@ -3845,8 +3861,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
if (send (sock, end, strlen (end), 0) < 0)
error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- /* Paranoia. */
- memset (password, 0, strlen (password));
+ /* Paranoia. */
+ memset (password, 0, strlen (password));
}
{
@@ -3939,20 +3955,28 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
return;
rejected:
+ error (0, 0,
+ "authorization failed: server %s rejected access to %s for user %s",
+ CVSroot_hostname, CVSroot_directory, CVSroot_username);
+
+ /* Output a special error message if authentication was attempted
+ with no password -- the user should be made aware that they may
+ have missed a step. */
+ if (no_passwd)
+ {
+ error (0, 0,
+ "used empty password; try \"cvs login\" with a real password");
+ }
+
if (shutdown (sock, 2) < 0)
{
- error (0, 0,
- "authorization failed: server %s rejected access",
- CVSroot_hostname);
- error (1, 0,
+ error (0, 0,
"shutdown() failed (server %s): %s",
CVSroot_hostname,
SOCK_STRERROR (SOCK_ERRNO));
}
- error (1, 0,
- "authorization failed: server %s rejected access",
- CVSroot_hostname);
+ error_exit();
}
#endif /* AUTH_CLIENT_SUPPORT */
@@ -4115,9 +4139,16 @@ connect_to_gserver (sock, hostinfo)
if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED)
{
OM_uint32 message_context;
+ OM_uint32 new_stat_min;
+
+ message_context = 0;
+ gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE,
+ GSS_C_NULL_OID, &message_context, &tok_out);
+ error (0, 0, "GSSAPI authentication failed: %s",
+ (char *) tok_out.value);
message_context = 0;
- gss_display_status (&stat_min, stat_maj, GSS_C_GSS_CODE,
+ gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE,
GSS_C_NULL_OID, &message_context, &tok_out);
error (1, 0, "GSSAPI authentication failed: %s",
(char *) tok_out.value);
@@ -4141,7 +4172,29 @@ connect_to_gserver (sock, hostinfo)
recv_bytes (sock, cbuf, 2);
need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff);
- assert (need <= sizeof buf);
+
+ if (need > sizeof buf)
+ {
+ int got;
+
+ /* This usually means that the server sent us an error
+ message. Read it byte by byte and print it out.
+ FIXME: This is a terrible error handling strategy.
+ However, even if we fix the server, we will still
+ 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",
+ CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO));
+ buf[got + 2] = '\0';
+ if (buf[got + 1] == '\n')
+ buf[got + 1] = '\0';
+ error (1, 0, "error from server %s: %s", CVSroot_hostname,
+ buf);
+ }
+
recv_bytes (sock, buf, need);
tok_in.length = need;
}
@@ -4175,7 +4228,7 @@ send_variable_proc (node, closure)
void
start_server ()
{
- int tofd, fromfd;
+ int tofd, fromfd, rootless;
char *log = getenv ("CVS_CLIENT_LOG");
@@ -4354,7 +4407,8 @@ the :server: access method is not supported by this port of CVS");
stored_mode = NULL;
}
- if (strcmp (command_name, "init") != 0)
+ rootless = (strcmp (command_name, "init") == 0);
+ if (!rootless)
{
send_to_server ("Root ", 0);
send_to_server (CVSroot_directory, 0);
@@ -4478,7 +4532,7 @@ the :server: access method is not supported by this port of CVS");
}
}
- if (cvsencrypt)
+ if (cvsencrypt && !rootless)
{
#ifdef ENCRYPTION
/* Turn on encryption before turning on compression. We do
@@ -4525,7 +4579,7 @@ the :server: access method is not supported by this port of CVS");
#endif /* ! ENCRYPTION */
}
- if (gzip_level)
+ if (gzip_level && !rootless)
{
if (supported_request ("Gzip-stream"))
{
@@ -4567,7 +4621,7 @@ the :server: access method is not supported by this port of CVS");
}
}
- if (cvsauthenticate && ! cvsencrypt)
+ if (cvsauthenticate && ! cvsencrypt && !rootless)
{
/* Turn on authentication after turning on compression, so
that we can compress the authentication information. We
@@ -4598,7 +4652,7 @@ the :server: access method is not supported by this port of CVS");
}
#ifdef FILENAMES_CASE_INSENSITIVE
- if (supported_request ("Case"))
+ if (supported_request ("Case") && !rootless)
send_to_server ("Case\012", 0);
#endif
@@ -4968,6 +5022,7 @@ struct send_data
int build_dirs;
int force;
int no_contents;
+ int backup_modified;
};
static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo));
@@ -5089,6 +5144,18 @@ warning: ignoring -k options due to server limitations");
}
else
send_modified (filename, finfo->fullname, vers);
+
+ if (args->backup_modified)
+ {
+ char *bakname;
+ bakname = backup_file (filename, vers->vn_user);
+ /* This behavior is sufficiently unexpected to
+ justify overinformativeness, I think. */
+ if (! really_quiet)
+ printf ("(Locally modified %s moved to %s)\n",
+ filename, bakname);
+ free (bakname);
+ }
}
else
{
@@ -5197,9 +5264,6 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries)
dir_exists = isdir (cvsadm_name);
free (cvsadm_name);
- /* initialize the ignore list for this directory */
- ignlist = getlist ();
-
/*
* If there is an empty directory (e.g. we are doing `cvs add' on a
* newly-created directory), the server still needs to know about it.
@@ -5215,6 +5279,9 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries)
char *repos = Name_Repository (dir, update_dir);
send_a_repository (dir, repos, update_dir);
free (repos);
+
+ /* initialize the ignore list for this directory */
+ ignlist = getlist ();
}
else
{
@@ -5239,6 +5306,29 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries)
return (dir_exists ? R_PROCESS : R_SKIP_ALL);
}
+static int send_dirleave_proc PROTO ((void *, char *, int, char *, List *));
+
+/*
+ * send_dirleave_proc () is called back by the recursion code upon leaving
+ * a directory. All it does is delete the ignore list if it hasn't already
+ * been done (by send_filesdone_proc).
+ */
+/* ARGSUSED */
+static int
+send_dirleave_proc (callerdat, dir, err, update_dir, entries)
+ void *callerdat;
+ char *dir;
+ int err;
+ char *update_dir;
+ List *entries;
+{
+
+ /* Delete the ignore list if it hasn't already been done. */
+ if (ignlist)
+ dellist (&ignlist);
+ return err;
+}
+
/*
* Send each option in a string to the server, one by one.
* This assumes that the options are separated by spaces, for example
@@ -5430,9 +5520,10 @@ send_files (argc, argv, local, aflag, flags)
args.build_dirs = flags & SEND_BUILD_DIRS;
args.force = flags & SEND_FORCE;
args.no_contents = flags & SEND_NO_CONTENTS;
+ args.backup_modified = flags & BACKUP_MODIFIED_FILES;
err = start_recursion
(send_fileproc, send_filesdoneproc,
- send_dirent_proc, (DIRLEAVEPROC)NULL, (void *) &args,
+ send_dirent_proc, send_dirleave_proc, (void *) &args,
argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0);
if (err)
error_exit ();
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 6dfd4a8..3d46e25 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -264,6 +264,7 @@ find_fileproc (callerdat, finfo)
else
error (0, 0, "use `%s add' to create an entry for %s",
program_name, finfo->fullname);
+ freevers_ts (&vers);
return 1;
}
else if (vers->ts_user != NULL
@@ -285,6 +286,7 @@ find_fileproc (callerdat, finfo)
cases. FIXME: we probably should be printing a message and
returning 1 for many of those cases (but I'm not sure
exactly which ones). */
+ freevers_ts (&vers);
return 0;
}
@@ -422,28 +424,12 @@ commit (argc, argv)
/* some checks related to the "-F logfile" option */
if (logfile)
{
- int n, logfd;
- struct stat statbuf;
+ size_t size = 0, len;
if (saved_message)
error (1, 0, "cannot specify both a message and a log file");
- /* FIXME: Why is this binary? Needs more investigation. */
- if ((logfd = CVS_OPEN (logfile, O_RDONLY | OPEN_BINARY)) < 0)
- error (1, errno, "cannot open log file %s", logfile);
-
- if (fstat(logfd, &statbuf) < 0)
- error (1, errno, "cannot find size of log file %s", logfile);
-
- saved_message = xmalloc (statbuf.st_size + 1);
-
- /* FIXME: Should keep reading until EOF, rather than assuming the
- first read gets the whole thing. */
- if ((n = read (logfd, saved_message, statbuf.st_size + 1)) < 0)
- error (1, errno, "cannot read log message from %s", logfile);
-
- (void) close (logfd);
- saved_message[n] = '\0';
+ get_file (logfile, logfile, "r", &saved_message, &size, &len);
}
#ifdef CLIENT_SUPPORT
@@ -474,11 +460,14 @@ commit (argc, argv)
error (1, 0, "correct above errors first!");
if (find_args.argc == 0)
+ {
/* Nothing to commit. Exit now without contacting the
server (note that this means that we won't print "?
foo" for files which merit it, because we don't know
what is in the CVSROOT/cvsignore file). */
+ dellist (&find_args.ulist);
return 0;
+ }
/* Now we keep track of which files we actually are going to
operate on, and only work with those files in the future.
@@ -584,6 +573,8 @@ commit (argc, argv)
previous versions of client/server CVS, but it probably is a Good
Thing, or at least Not Such A Bad Thing. */
send_file_names (find_args.argc, find_args.argv, 0);
+ free (find_args.argv);
+ dellist (&find_args.ulist);
send_to_server ("ci\012", 0);
err = get_responses_and_close ();
@@ -673,16 +664,11 @@ commit (argc, argv)
Lock_Cleanup ();
dellist (&mulist);
+ /* see if we need to sleep before returning to avoid time-stamp races */
if (last_register_time)
{
- time_t now;
-
- for (;;)
- {
- (void) time (&now);
- if (now != last_register_time) break;
- sleep (1); /* to avoid time-stamp races */
- }
+ while (time ((time_t *) NULL) == last_register_time)
+ sleep (1);
}
return (err);
@@ -795,6 +781,12 @@ check_fileproc (callerdat, finfo)
size_t cvsroot_len = strlen (CVSroot_directory);
+ if (!finfo->repository)
+ {
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
+ return (1);
+ }
+
if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0
&& ISDIRSEP (finfo->repository[cvsroot_len])
&& strncmp (finfo->repository + cvsroot_len + 1,
@@ -1291,6 +1283,8 @@ commit_fileproc (callerdat, finfo)
{
if (finfo->rcs == NULL)
error (1, 0, "internal error: no parsed RCS file");
+ if (ci->rev)
+ free (ci->rev);
ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
ci->tag, ci->options, saved_message);
@@ -1401,6 +1395,8 @@ out:
}
}
}
+ if (SIG_inCrSect ())
+ SIG_endCrSect ();
return (err);
}
@@ -1501,6 +1497,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
cvs_output (": Executing '", 0);
run_print (stdout);
cvs_output ("'\n", 0);
+ cvs_flushout ();
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
free (repos);
}
@@ -1583,8 +1580,10 @@ commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
this being a confusing feature! */
if (err == 0 && write_dirtag != NULL)
{
+ char *repos = Name_Repository (dir, update_dir);
WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
- update_dir, Name_Repository (dir, update_dir));
+ update_dir, repos);
+ free (repos);
}
return (err);
@@ -1752,6 +1751,9 @@ remove_file (finfo, tag, message)
"failed to commit dead revision for `%s'", finfo->fullname);
return (1);
}
+ /* At this point, the file has been committed as removed. We should
+ probably tell the history file about it */
+ history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository);
if (rev != NULL)
free (rev);
@@ -1963,6 +1965,11 @@ checkaddfile (file, repository, tag, options, rcsnode)
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+ /* Begin a critical section around the code that spans the
+ first commit on the trunk of a file that's already been
+ committed on a branch. */
+ SIG_beginCrSect ();
+
if (RCS_setattic (rcsfile, 0))
{
retval = 1;
@@ -2045,74 +2052,76 @@ checkaddfile (file, repository, tag, options, rcsnode)
newfile = 1;
if (desc != NULL)
free (desc);
+ if (rcsnode != NULL)
+ {
+ assert (*rcsnode == NULL);
+ *rcsnode = rcsfile;
+ }
}
/* when adding a file for the first time, and using a tag, we need
to create a dead revision on the trunk. */
- if (adding_on_branch && newfile)
+ if (adding_on_branch)
{
- char *tmp;
- FILE *fp;
-
- /* move the new file out of the way. */
- fname = xmalloc (strlen (file) + sizeof (CVSADM)
- + sizeof (CVSPREFIX) + 10);
- (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
- rename_file (file, fname);
-
- /* Create empty FILE. Can't use copy_file with a DEVNULL
- argument -- copy_file now ignores device files. */
- fp = fopen (file, "w");
- if (fp == NULL)
- error (1, errno, "cannot open %s for writing", file);
- if (fclose (fp) < 0)
- error (0, errno, "cannot close %s", file);
-
- tmp = xmalloc (strlen (file) + strlen (tag) + 80);
- /* commit a dead revision. */
- (void) sprintf (tmp, "file %s was initially added on branch %s.",
- file, tag);
- retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
- RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
- free (tmp);
- if (retcode != 0)
+ if (newfile)
{
- error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
- "could not create initial dead revision %s", rcs);
- retval = 1;
- goto out;
- }
+ char *tmp;
+ FILE *fp;
- /* put the new file back where it was */
- rename_file (fname, file);
- free (fname);
+ /* move the new file out of the way. */
+ fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ + sizeof (CVSPREFIX) + 10);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
+ rename_file (file, fname);
- /* double-check that the file was written correctly */
- freercsnode (&rcsfile);
- rcsfile = RCS_parse (file, repository);
- if (rcsfile == NULL)
- {
- error (0, 0, "could not read %s", rcs);
- retval = 1;
- goto out;
- }
- if (rcsnode != NULL)
- {
- assert (*rcsnode == NULL);
- *rcsnode = rcsfile;
- }
+ /* Create empty FILE. Can't use copy_file with a DEVNULL
+ argument -- copy_file now ignores device files. */
+ fp = fopen (file, "w");
+ if (fp == NULL)
+ error (1, errno, "cannot open %s for writing", file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", file);
+
+ tmp = xmalloc (strlen (file) + strlen (tag) + 80);
+ /* commit a dead revision. */
+ (void) sprintf (tmp, "file %s was initially added on branch %s.",
+ file, tag);
+ retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
+ RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
+ free (tmp);
+ if (retcode != 0)
+ {
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
+ "could not create initial dead revision %s", rcs);
+ retval = 1;
+ goto out;
+ }
- /* and lock it once again. */
- if (lock_RCS (file, rcsfile, NULL, repository))
- {
- error (0, 0, "cannot lock `%s'.", rcs);
- retval = 1;
- goto out;
+ /* put the new file back where it was */
+ rename_file (fname, file);
+ free (fname);
+
+ /* double-check that the file was written correctly */
+ freercsnode (&rcsfile);
+ rcsfile = RCS_parse (file, repository);
+ if (rcsfile == NULL)
+ {
+ error (0, 0, "could not read %s", rcs);
+ retval = 1;
+ goto out;
+ }
+ if (rcsnode != NULL)
+ *rcsnode = rcsfile;
+
+ /* and lock it once again. */
+ if (lock_RCS (file, rcsfile, NULL, repository))
+ {
+ error (0, 0, "cannot lock `%s'.", rcs);
+ retval = 1;
+ goto out;
+ }
}
- }
- if (adding_on_branch)
- {
/* when adding with a tag, we need to stub a branch, if it
doesn't already exist. */
@@ -2197,6 +2206,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
retval = 0;
out:
+ if (retval != 0 && SIG_inCrSect ())
+ SIG_endCrSect ();
free (rcs);
return retval;
}
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index b889c9a..6489f07 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -395,6 +395,7 @@ extern List *root_directories;
extern char *current_root;
extern char *emptydir_name PROTO ((void));
+extern int safe_location PROTO ((void));
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
@@ -507,7 +508,7 @@ void *valloc PROTO((size_t bytes));
time_t get_date PROTO((char *date, struct timeb *now));
extern int Create_Admin PROTO ((char *dir, char *update_dir,
char *repository, char *tag, char *date,
- int nonbranch, int warn));
+ int nonbranch, int warn, int dotemplate));
extern int expand_at_signs PROTO ((char *, off_t, FILE *));
/* Locking subsystem (implemented in lock.c). */
@@ -533,7 +534,7 @@ void cat_module PROTO((int status));
void check_entries PROTO((char *dir));
void close_module PROTO((DBM * db));
void copy_file PROTO((const char *from, const char *to));
-void fperror PROTO((FILE * fp, int status, int errnum, char *message,...));
+void fperrmsg PROTO((FILE * fp, int status, int errnum, char *message,...));
void free_names PROTO((int *pargc, char *argv[]));
extern int ign_name PROTO ((char *name));
@@ -554,6 +555,7 @@ void make_directories PROTO((const char *name));
void make_directory PROTO((const char *name));
extern int mkdir_if_needed PROTO ((char *name));
void rename_file PROTO((const char *from, const char *to));
+char *backup_file PROTO((const char *file, const char *suffix));
/* Expand wildcards in each element of (ARGC,ARGV). This is according to the
files which exist in the current directory, and accordingly to OS-specific
conventions regarding wildcard syntax. It might be desirable to change the
@@ -585,7 +587,7 @@ void do_editor PROTO((char *dir, char **messagep,
void do_verify PROTO((char **messagep, char *repository));
-typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
+typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten, int local_specified,
char *omodule, char *msg));
@@ -644,6 +646,7 @@ int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc,
int dosrcs));
void SIG_beginCrSect PROTO((void));
void SIG_endCrSect PROTO((void));
+int SIG_inCrSect PROTO((void));
void read_cvsrc PROTO((int *argc, char ***argv, char *cmdname));
char *make_message_rcslegal PROTO((char *message));
@@ -861,6 +864,7 @@ extern int cvsremove PROTO((int argc, char **argv));
extern int rtag PROTO((int argc, char **argv));
extern int cvsstatus PROTO((int argc, char **argv));
extern int cvstag PROTO((int argc, char **argv));
+extern int version PROTO((int argc, char **argv));
extern unsigned long int lookup_command_attribute PROTO((char *));
@@ -877,6 +881,8 @@ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *));
extern void tag_check_valid_join PROTO ((char *, int, char **, int, int,
char *));
+#include "server.h"
+
/* From server.c and documented there. */
extern void cvs_output PROTO ((const char *, size_t));
extern void cvs_output_binary PROTO ((char *, size_t));
@@ -884,7 +890,3 @@ extern void cvs_outerr PROTO ((const char *, size_t));
extern void cvs_flusherr PROTO ((void));
extern void cvs_flushout PROTO ((void));
extern void cvs_output_tagged PROTO ((char *, char *));
-
-#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
-#include "server.h"
-#endif
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
index 7572558..2cccbcd 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -55,9 +55,13 @@ copy_file (from, to)
if (isdevice (from))
{
+#if defined(HAVE_MKNOD) && defined(HAVE_ST_RDEV)
if (stat (from, &sb) < 0)
error (1, errno, "cannot stat %s", from);
mknod (to, sb.st_mode, sb.st_rdev);
+#else
+ error (1, 0, "cannot copy device files on this system (%s)", from);
+#endif
}
else
{
@@ -624,10 +628,15 @@ xcmp (file1, file2)
numbers match. */
if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode))
{
+#ifdef HAVE_ST_RDEV
if (sb1.st_rdev == sb2.st_rdev)
return 0;
else
return 1;
+#else
+ error (1, 0, "cannot compare device files on this system (%s and %s)",
+ file1, file2);
+#endif
}
if ((fd1 = open (file1, O_RDONLY)) < 0)
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index a449842..3f77dc9 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -268,12 +268,22 @@ import (argc, argv)
client_import_setup (repository);
err = import_descend (message, argv[1], argc - 2, argv + 2);
client_import_done ();
+ if (message)
+ free (message);
+ free (repository);
+ free (vbranch);
+ free (vhead);
send_to_server ("import\012", 0);
err += get_responses_and_close ();
return err;
}
#endif
+ if (!safe_location ())
+ {
+ error (1, 0, "attempt to import the repository");
+ }
+
/*
* Make all newly created directories writable. Should really use a more
* sophisticated security mechanism here.
@@ -455,9 +465,12 @@ 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 && islink (dp->d_name))
+#else
+ islink (dp->d_name)
#endif
- islink (dp->d_name))
+ )
{
add_log ('L', dp->d_name);
err++;
@@ -727,8 +740,8 @@ add_rev (message, rcs, vfile, vers)
{
if (!noexec)
{
- fperror (logfp, 0, status == -1 ? ierrno : 0,
- "ERROR: Check-in of %s failed", rcs->path);
+ fperrmsg (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);
}
@@ -767,8 +780,8 @@ 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->path);
+ fperrmsg (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->path);
return (1);
@@ -791,9 +804,9 @@ add_tags (rcs, vfile, vtag, targc, targv)
else
{
ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "WARNING: Couldn't add tag %s to %s", targv[i],
- rcs->path);
+ fperrmsg (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->path);
@@ -1056,7 +1069,14 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
stat the file before opening it. -twp */
if (CVS_LSTAT (userfile, &sb) < 0)
- error (1, errno, "cannot lstat %s", user);
+ {
+ /* not fatal, continue import */
+ if (add_logfp != NULL)
+ fperrmsg (add_logfp, 0, errno,
+ "ERROR: cannot lstat file %s", userfile);
+ error (0, errno, "cannot lstat file %s", userfile);
+ goto read_error;
+ }
file_type = sb.st_mode & S_IFMT;
fpuser = NULL;
@@ -1071,8 +1091,8 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
{
/* not fatal, continue import */
if (add_logfp != NULL)
- fperror (add_logfp, 0, errno,
- "ERROR: cannot read file %s", userfile);
+ fperrmsg (add_logfp, 0, errno,
+ "ERROR: cannot read file %s", userfile);
error (0, errno, "ERROR: cannot read file %s", userfile);
goto read_error;
}
@@ -1204,12 +1224,18 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
case S_IFREG: break;
case S_IFCHR:
case S_IFBLK:
+#ifdef HAVE_ST_RDEV
if (fprintf (fprcs, "special\t%s %lu;\012",
(file_type == S_IFCHR
? "character"
: "block"),
(unsigned long) sb.st_rdev) < 0)
goto write_error;
+#else
+ error (0, 0,
+"can't import %s: unable to import device files on this system",
+userfile);
+#endif
break;
default:
error (0, 0,
@@ -1255,12 +1281,18 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
case S_IFREG: break;
case S_IFCHR:
case S_IFBLK:
+#ifdef HAVE_ST_RDEV
if (fprintf (fprcs, "special\t%s %lu;\012",
(file_type == S_IFCHR
? "character"
: "block"),
(unsigned long) sb.st_rdev) < 0)
goto write_error;
+#else
+ error (0, 0,
+"can't import %s: unable to import device files on this system",
+userfile);
+#endif
break;
default:
error (0, 0,
@@ -1379,8 +1411,8 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
{
ierrno = errno;
if (add_logfp != NULL)
- fperror (add_logfp, 0, ierrno,
- "WARNING: cannot change mode of file %s", rcs);
+ fperrmsg (add_logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
err++;
}
@@ -1399,14 +1431,14 @@ write_error_noclose:
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);
+ fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
error (0, ierrno, "ERROR: cannot write file %s", rcs);
if (ierrno == ENOSPC)
{
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");
+ fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
error (1, 0, "ERROR: out of space - aborting");
}
read_error:
@@ -1515,7 +1547,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
return (0);
if (save_cwd (&cwd))
{
- fperror (logfp, 0, 0, "ERROR: cannot get working directory");
+ fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
return (1);
}
@@ -1546,7 +1578,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
if ( CVS_CHDIR (dir) < 0)
{
ierrno = errno;
- fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
+ fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
error (0, ierrno, "ERROR: cannot chdir to %s", repository);
err = 1;
goto out;
@@ -1561,9 +1593,9 @@ import_descend_dir (message, dir, vtag, targc, targv)
(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!",
- repository);
+ fperrmsg (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);
err = 1;
@@ -1572,8 +1604,8 @@ import_descend_dir (message, dir, vtag, targc, targv)
if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
{
ierrno = errno;
- fperror (logfp, 0, ierrno,
- "ERROR: cannot mkdir %s -- not added", repository);
+ fperrmsg (logfp, 0, ierrno,
+ "ERROR: cannot mkdir %s -- not added", repository);
error (0, ierrno,
"ERROR: cannot mkdir %s -- not added", repository);
err = 1;
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index a0c0a34..30c72f9 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -177,8 +177,12 @@ lock_name (repository, name)
assert (CVSroot_directory != NULL);
assert (strncmp (repository, CVSroot_directory,
strlen (CVSroot_directory)) == 0);
- short_repos = repository + strlen (CVSroot_directory);
- assert (*short_repos++ == '/');
+ short_repos = repository + strlen (CVSroot_directory) + 1;
+
+ if (strcmp (repository, CVSroot_directory) == 0)
+ short_repos = ".";
+ else
+ assert (short_repos[-1] == '/');
retval = xmalloc (strlen (lock_dir)
+ strlen (short_repos)
@@ -762,8 +766,8 @@ set_lock (lock, will_wait)
if (errno != EEXIST)
{
error (0, errno,
- "failed to create lock directory in repository `%s'",
- lock->repository);
+ "failed to create lock directory for `%s' (%s)",
+ lock->repository, masterlock);
return (L_ERROR);
}
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
index 708dfc8..cc564c06 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -14,6 +14,12 @@
#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
+#ifdef HAVE_GETPASSPHRASE
+#define GETPASS getpassphrase
+#else
+#define GETPASS getpass
+#endif
+
/* There seems to be very little agreement on which system header
getpass is declared in. With a lot of fancy autoconfiscation,
we could perhaps detect this, but for now we'll just rely on
@@ -22,7 +28,7 @@
varadic, believe it or not). On Cray, getpass will be declared
in either stdlib.h or unistd.h. */
#ifndef _CRAY
-extern char *getpass ();
+extern char *GETPASS ();
#endif
#ifndef CVS_PASSWORD_FILE
@@ -144,7 +150,7 @@ login (argc, argv)
fflush (stdout);
passfile = construct_cvspass_filename ();
- typed_password = getpass ("CVS password: ");
+ typed_password = GETPASS ("CVS password: ");
typed_password = scramble (typed_password);
/* Force get_cvs_password() to use this one (when the client
@@ -291,21 +297,19 @@ login (argc, argv)
}
/* Returns the _scrambled_ password. The server must descramble
- before hashing and comparing. */
+ before hashing and comparing. If password file not found, or
+ password not found in the file, just return NULL. */
char *
get_cvs_password ()
{
int found_it = 0;
int root_len;
- char *password;
- char *linebuf = (char *) NULL;
+ char *password = NULL;
+ char *linebuf = NULL;
size_t linebuf_len;
FILE *fp;
char *passfile;
int line_length;
- int anoncvs;
-
- anoncvs = (strcmp(CVSroot_username, "anoncvs") == 0);
/* If someone (i.e., login()) is calling connect_to_pserver() out of
context, then assume they have supplied the correct, scrambled
@@ -344,15 +348,10 @@ get_cvs_password ()
passfile = construct_cvspass_filename ();
fp = CVS_FOPEN (passfile, "r");
- if (fp == NULL)
+ if (fp == NULL)
{
- if (anoncvs) {
- free (passfile);
- return strdup("Ay=0=h<Z"); /* scrambled "anoncvs" */
- }
- error (0, errno, "could not open %s", passfile);
free (passfile);
- error (1, 0, "use \"cvs login\" to log in first");
+ return NULL;
}
root_len = strlen (CVSroot_original);
@@ -371,7 +370,6 @@ get_cvs_password ()
error (0, errno, "cannot read %s", passfile);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", passfile);
- free (passfile);
if (found_it)
{
@@ -379,25 +377,19 @@ get_cvs_password ()
char *tmp;
strtok (linebuf, " ");
- password = strtok (NULL, "\n");
+ tmp = strtok (NULL, "\n");
+ if (tmp == NULL)
+ error (1, 0, "bad entry in %s for %s", passfile, CVSroot_original);
/* Give it permanent storage. */
- tmp = xstrdup (password);
- memset (password, 0, strlen (password));
- free (linebuf);
- return tmp;
+ password = xstrdup (tmp);
+ memset (tmp, 0, strlen (password));
}
- else
- {
- if (linebuf)
- free (linebuf);
- if (anoncvs)
- return strdup("Ay=0=h<Z"); /* scrambled "anoncvs" */
- error (0, 0, "cannot find password");
- error (1, 0, "use \"cvs login\" to log in first");
- }
- /* NOTREACHED */
- return NULL;
+
+ if (linebuf)
+ free (linebuf);
+ free (passfile);
+ return password;
}
static const char *const logout_usage[] =
@@ -407,7 +399,7 @@ static const char *const logout_usage[] =
NULL
};
-/* Remove any entry for the CVSRoot repository found in "CVS/.cvspass". */
+/* Remove any entry for the CVSRoot repository found in .cvspass. */
int
logout (argc, argv)
int argc;
@@ -415,7 +407,7 @@ logout (argc, argv)
{
char *passfile;
FILE *fp;
- char *tmp_name;
+ char *tmp_name = NULL;
FILE *tmp_fp;
char *linebuf = (char *) NULL;
size_t linebuf_len;
@@ -510,6 +502,10 @@ logout (argc, argv)
error (0, errno, "cannot remove %s", tmp_name);
chmod (passfile, 0600);
}
+
+ if (tmp_name)
+ free (tmp_name);
+
return 0;
}
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index e1b8ed0..a5e16b7 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -184,7 +184,6 @@ do_editor (dir, messagep, repository, changes)
char *fname;
struct stat pre_stbuf, post_stbuf;
int retcode = 0;
- char *p;
if (noexec || reuse_log_message)
return;
@@ -218,7 +217,6 @@ do_editor (dir, messagep, repository, changes)
{
FILE *tfp;
char buf[1024];
- char *p;
size_t n;
size_t nwrite;
@@ -233,9 +231,9 @@ do_editor (dir, messagep, repository, changes)
{
while (!feof (tfp))
{
+ char *p = buf;
n = fread (buf, 1, sizeof buf, tfp);
nwrite = n;
- p = buf;
while (nwrite > 0)
{
n = fwrite (p, 1, nwrite, fp);
@@ -317,7 +315,8 @@ do_editor (dir, messagep, repository, changes)
if (*messagep)
{
- p = *messagep;
+ size_t message_len = post_stbuf.st_size + 1;
+ size_t offset = 0;
while (1)
{
line_length = getline (&line, &line_chars_allocated, fp);
@@ -329,8 +328,11 @@ do_editor (dir, messagep, repository, changes)
}
if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
continue;
- (void) strcpy (p, line);
- p += line_length;
+ if (offset + line_length >= message_len)
+ expand_string (messagep, &message_len,
+ offset + line_length + 1);
+ (void) strcpy (*messagep + offset, line);
+ offset += line_length;
}
}
if (fclose (fp) < 0)
@@ -816,7 +818,7 @@ logfile_write (repository, filter, message, logfp, changes)
}
len = fmt_end - fmt_begin;
- str_list_format = xmalloc (sizeof (char) * (len + 1));
+ str_list_format = xmalloc (len + 1);
strncpy (str_list_format, fmt_begin, len);
str_list_format[len] = '\0';
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index 39bfaa2..cad210b 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -115,30 +115,31 @@ static const struct cmd
{ "history", "hi", "his", history },
{ "import", "im", "imp", import },
{ "init", NULL, NULL, init },
-#ifdef SERVER_SUPPORT
+#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
{ "kserver", NULL, NULL, server }, /* placeholder */
#endif
{ "log", "lo", "rlog", cvslog },
#ifdef AUTH_CLIENT_SUPPORT
{ "login", "logon", "lgn", login },
{ "logout", NULL, NULL, logout },
-#ifdef SERVER_SUPPORT
+#endif /* AUTH_CLIENT_SUPPORT */
+#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
{ "pserver", NULL, NULL, server }, /* placeholder */
#endif
-#endif /* AUTH_CLIENT_SUPPORT */
{ "rdiff", "patch", "pa", patch },
{ "release", "re", "rel", release },
{ "remove", "rm", "delete", cvsremove },
- { "status", "st", "stat", cvsstatus },
{ "rtag", "rt", "rfreeze", rtag },
+#ifdef SERVER_SUPPORT
+ { "server", NULL, NULL, server },
+#endif
+ { "status", "st", "stat", cvsstatus },
{ "tag", "ta", "freeze", cvstag },
{ "unedit", NULL, NULL, unedit },
{ "update", "up", "upd", update },
+ { "version", "ve", "ver", version },
{ "watch", NULL, NULL, watch },
{ "watchers", NULL, NULL, watchers },
-#ifdef SERVER_SUPPORT
- { "server", NULL, NULL, server },
-#endif
{ NULL, NULL, NULL, NULL },
};
@@ -183,7 +184,7 @@ static const char *const usg[] =
version control means. */
"For CVS updates and additional information, see\n",
- " Cyclic Software at http://www.cyclic.com/ or\n",
+ " the CVS home page at http://www.cvshome.org/ or\n",
" Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
NULL,
};
@@ -203,15 +204,24 @@ static const char *const cmd_usage[] =
" history Show repository access history\n",
" import Import sources into CVS, using vendor branches\n",
" init Create a CVS repository if it doesn't exist\n",
+#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
+ " kserver Kerberos server mode\n",
+#endif
" log Print out history information for files\n",
#ifdef AUTH_CLIENT_SUPPORT
- " login Prompt for password for authenticating server.\n",
- " logout Removes entry in .cvspass for remote repository.\n",
+ " login Prompt for password for authenticating server\n",
+ " logout Removes entry in .cvspass for remote repository\n",
#endif /* AUTH_CLIENT_SUPPORT */
+#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
+ " pserver Password server mode\n",
+#endif
" rdiff Create 'patch' format diffs between releases\n",
" release Indicate that a Module is no longer in use\n",
" remove Remove an entry from the repository\n",
" rtag Add a symbolic tag to a module\n",
+#ifdef SERVER_SUPPORT
+ " server Server mode\n",
+#endif
" status Display status information on checked out files\n",
" tag Add a symbolic tag to checked out version of files\n",
" unedit Undo an edit command\n",
@@ -349,6 +359,7 @@ lookup_command_attribute (cmd_name)
(strcmp (cmd_name, "log") != 0) &&
(strcmp (cmd_name, "noop") != 0) &&
(strcmp (cmd_name, "watchers") != 0) &&
+ (strcmp (cmd_name, "release") != 0) &&
(strcmp (cmd_name, "status") != 0))
{
ret |= CVS_CMD_MODIFIES_REPOSITORY;
@@ -368,6 +379,11 @@ main_cleanup (sig)
switch (sig)
{
+#ifdef SIGABRT
+ case SIGABRT:
+ name = "abort";
+ break;
+#endif
#ifdef SIGHUP
case SIGHUP:
name = "hangup";
@@ -411,8 +427,6 @@ main (argc, argv)
char **argv;
{
char *CVSroot = CVSROOT_DFLT;
- extern char *version_string;
- extern char *config_string;
char *cp, *end;
const struct cmd *cm;
int c, err = 0;
@@ -424,6 +438,7 @@ main (argc, argv)
int help = 0; /* Has the user asked for help? This
lets us support the `cvs -H cmd'
convention to give help for cmd. */
+ static const char short_options[] = "+QqgrwtnRlvb:T:e:d:Hfz:s:xaU";
static struct option long_options[] =
{
{"help", 0, NULL, 'H'},
@@ -504,7 +519,7 @@ main (argc, argv)
opterr = 0;
while ((c = getopt_long
- (argc, argv, "+f", NULL, NULL))
+ (argc, argv, short_options, long_options, &option_index))
!= EOF)
{
if (c == 'f')
@@ -521,7 +536,7 @@ main (argc, argv)
opterr = 1;
while ((c = getopt_long
- (argc, argv, "+QqgrwtnRlvb:T:e:d:Hfz:s:xaU", long_options, &option_index))
+ (argc, argv, short_options, long_options, &option_index))
!= EOF)
{
switch (c)
@@ -574,14 +589,11 @@ main (argc, argv)
logoff = 1;
break;
case 'v':
- /* Having the year here is a good idea, so people have
- some idea of how long ago their version of CVS was
- released. */
- (void) fputs (version_string, stdout);
- (void) fputs (config_string, stdout);
+ (void) fputs ("\n", stdout);
+ version (0, (char **) NULL);
(void) fputs ("\n", stdout);
(void) fputs ("\
-Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
+Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\
Jeff Polk, and other authors\n", stdout);
(void) fputs ("\n", stdout);
(void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
@@ -625,9 +637,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
case 'z':
#ifdef CLIENT_SUPPORT
gzip_level = atoi (optarg);
- if (gzip_level <= 0 || gzip_level > 9)
+ if (gzip_level < 0 || gzip_level > 9)
error (1, 0,
- "gzip compression level must be between 1 and 9");
+ "gzip compression level must be between 0 and 9");
#endif
/* If no CLIENT_SUPPORT, we just silently ignore the gzip
level, so that users can have it in their .cvsrc and not
@@ -685,7 +697,10 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
}
if (!cm->fullname)
- usage (cmd_usage); /* no match */
+ {
+ fprintf (stderr, "Unknown command: `%s'\n\n", command_name);
+ usage (cmd_usage);
+ }
else
command_name = cm->fullname; /* Global pointer for later use */
@@ -799,25 +814,23 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
#ifndef DONT_USE_SIGNALS
/* make sure we clean up on error */
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, main_cleanup);
+#endif
#ifdef SIGHUP
(void) SIG_register (SIGHUP, main_cleanup);
- (void) SIG_register (SIGHUP, Lock_Cleanup);
#endif
#ifdef SIGINT
(void) SIG_register (SIGINT, main_cleanup);
- (void) SIG_register (SIGINT, Lock_Cleanup);
#endif
#ifdef SIGQUIT
(void) SIG_register (SIGQUIT, main_cleanup);
- (void) SIG_register (SIGQUIT, Lock_Cleanup);
#endif
#ifdef SIGPIPE
(void) SIG_register (SIGPIPE, main_cleanup);
- (void) SIG_register (SIGPIPE, Lock_Cleanup);
#endif
#ifdef SIGTERM
(void) SIG_register (SIGTERM, main_cleanup);
- (void) SIG_register (SIGTERM, Lock_Cleanup);
#endif
#endif /* !DONT_USE_SIGNALS */
@@ -912,7 +925,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
{
Node *n;
n = getnode ();
- n->type = UNKNOWN;
+ n->type = NT_UNKNOWN;
n->key = xstrdup (CVSroot);
n->data = NULL;
@@ -955,11 +968,8 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
current_root);
/*
- * Check to see if we can write into the history file. If not,
- * we assume that we can't work in the repository.
- * BUT, only if the history file exists.
+ * Check to see if the repository exists.
*/
-
if (!client_active)
{
char *path;
@@ -967,8 +977,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
path = xmalloc (strlen (CVSroot_directory)
+ sizeof (CVSROOTADM)
- + 20
- + sizeof (CVSROOTADM_HISTORY));
+ + 20);
(void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
@@ -979,14 +988,6 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
error (1, save_errno, "%s", path);
}
}
- (void) strcat (path, "/");
- (void) strcat (path, CVSROOTADM_HISTORY);
- if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
- {
- save_errno = errno;
- error (0, 0, "Sorry, you don't have read/write access to the history file");
- error (1, save_errno, "%s", path);
- }
free (path);
}
@@ -995,12 +996,17 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
/* FIXME (njc): should we always set this with the CVSROOT from the command line? */
if (cvs_update_env)
{
+ static char *prev;
char *env;
env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
+ 1 + 1);
(void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
(void) putenv (env);
- /* do not free env, as putenv has control of it */
+ /* do not free env yet, as putenv has control of it */
+ /* but do free the previous value, if any */
+ if (prev != NULL)
+ free (prev);
+ prev = env;
}
#endif
}
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index 966fb328..49cda18 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -283,14 +283,23 @@ static const char *const config_contents[] = {
"# Set this to \"no\" if pserver shouldn't check system users/passwords\n",
"#SystemAuth=no\n",
"\n",
+ "# Put CVS lock files in this directory rather than directly in the repository.\n",
+ "#LockDir=/var/lock/cvs\n",
+ "\n",
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
"# Set `PreservePermissions' to `yes' to save file status information\n",
"# in the repository.\n",
"#PreservePermissions=no\n",
"\n",
+#endif
"# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n",
"# level of the new working directory when using the `cvs checkout'\n",
"# command.\n",
"#TopLevelAdmin=no\n",
+ "\n",
+ "# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n",
+ "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
+ "#LogHistory=TOFEWGCMAR\n",
NULL
};
@@ -375,6 +384,9 @@ mkmodules (dir)
size_t line_allocated = 0;
const struct admin_file *fileptr;
+ if (noexec)
+ return 0;
+
if (save_cwd (&cwd))
error_exit ();
@@ -868,6 +880,9 @@ init (argc, argv)
if ( CVS_CHDIR (adm) < 0)
error (1, errno, "cannot change to directory %s", adm);
+ /* Make Emptydir so it's there if we need it */
+ mkdir_if_needed (CVSNULLREPOS);
+
/* 80 is long enough for all the administrative file names, plus
"/" and so on. */
info = xmalloc (strlen (adm) + 80);
@@ -929,6 +944,29 @@ init (argc, argv)
fp = open_file (info, "w");
if (fclose (fp) < 0)
error (1, errno, "cannot close %s", info);
+
+ /* Make the new history file world-writeable, since every CVS
+ user will need to be able to write to it. We use chmod()
+ because xchmod() is too shy. */
+ chmod (info, 0666);
+ }
+
+ /* Make an empty val-tags file to prevent problems creating it later. */
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, CVSROOTADM_VALTAGS);
+ if (!isfile (info))
+ {
+ FILE *fp;
+
+ fp = open_file (info, "w");
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+
+ /* Make the new val-tags file world-writeable, since every CVS
+ user will need to be able to write to it. We use chmod()
+ because xchmod() is too shy. */
+ chmod (info, 0666);
}
free (info);
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 48be8e5..7f2094d8 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -62,6 +62,7 @@ static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
char **valp));
+static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
size_t *lenp));
static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
@@ -158,6 +159,7 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
static char *rcs_lockfile;
+static int rcs_lockfd = -1;
/* A few generic thoughts on error handling, in particular the
printing of unexpected characters that we find in the RCS file
@@ -546,9 +548,10 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
if (rdata->other == NULL)
rdata->other = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (rdata->other, kv) != 0)
{
error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
@@ -594,9 +597,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
key, rcsfile);
free (rdata->desc);
}
- /* Don't need to rcsbuf_valcopy `value' because
- getdelta already did that. */
- rdata->desc = xstrdup (value);
+ rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
}
rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
@@ -752,9 +753,10 @@ RCS_fully_parse (rcs)
if (vnode->other == NULL)
vnode->other = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (vnode->other, kv) != 0)
{
error (0, 0,
@@ -1032,6 +1034,9 @@ rcsbuf_close (rcsbuf)
characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
appropriate massaging. */
+/* Note that the extreme hair in rcsbuf_getkey is because profiling
+ statistics show that it was worth it. */
+
static int
rcsbuf_getkey (rcsbuf, keyp, valp)
struct rcsbuffer *rcsbuf;
@@ -1287,13 +1292,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
}
/* The value extends past the '@' string. We need to undo the
- closing of the '@' done in the default case above. This
+ '@' stripping done in the default case above. This
case never happens in a plain RCS file, but it can happen
if user defined phrases are used. */
- if (rcsbuf->vlen != 0)
- (*valp)[rcsbuf->vlen] = ' ';
- else
- *valp = ptr;
+ ((*valp)--)[rcsbuf->vlen++] = '@';
}
/* Here we have a value which is not a simple '@' string. We need
@@ -1350,8 +1352,8 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
return 1;
}
- /* We found an '@' string in the value. We set
- RCSBUF->AT_STRING, which means that we won't be able to
+ /* We found an '@' string in the value. We set RCSBUF->AT_STRING
+ and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
compress whitespace correctly for this type of value.
Since this type of value never arises in a normal RCS file,
this should not be a big deal. It means that if anybody
@@ -1360,8 +1362,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
themselves. */
rcsbuf->at_string = 1;
-
- *pat = ' ';
+ rcsbuf->embedded_at = -1;
ptr = pat + 1;
@@ -1396,495 +1397,16 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
break;
/* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
ptr = pat + 2;
}
/* Here PAT points to the final '@' in the string. */
-
- *pat = ' ';
-
ptr = pat + 1;
}
#undef my_whitespace
}
-/* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid,
- rcsbuf_getstring, rcsbuf_getword. These last three functions were
- all created by hacking monstrous swaths of code from rcsbuf_getkey,
- and some engineering would make the code easier to read and
- maintain.
-
- Note that the extreme hair in rcsbuf_getkey is because profiling
- statistics show that it was worth it.
-
- We probably could be processing "hardlinks" by first calling
- rcsbuf_getkey, and breaking up the value afterwards; the code to
- break it up would not need to be hacked for speed. This would
- remove the need for rcsbuf_getword, rcsbuf_getid, and
- rcsbuf_getstring, as the other calls are easy to remove. */
-
-/* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in
- IDP. */
-
-static int
-rcsbuf_getid (rcsbuf, idp)
- struct rcsbuffer *rcsbuf;
- char **idp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- return 0;
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* We've found the start of the key. */
-
- *idp = ptr;
-
- if (c != ';')
- {
- while (1)
- {
- ++ptr;
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "EOF in key in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- c = *ptr;
- if (c == ';' || my_whitespace (c))
- break;
- }
- }
-
- /* Here *IDP points to the id in the buffer, C is the character
- we found at the end of the key, and PTR points to the location in
- the buffer where we found C. We may not set *PTR to \0, because
- it may overwrite a terminating semicolon. The calling function
- must copy and terminate the id on its own. */
-
- rcsbuf->ptr = ptr;
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS @-delimited string. Store the result in STRP. */
-
-static int
-rcsbuf_getstring (rcsbuf, strp)
- struct rcsbuffer *rcsbuf;
- char **strp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char *pat;
- size_t vlen;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* PTR should now point to the start of a string. */
- if (c != '@')
- error (1, 0, "expected @-string at '\\x%x' in %s",
- c, rcsbuf->filename);
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *strp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, strp);
- if (pat == NULL)
- {
- /* EOF here is OK; it just means that the last
- character of the file was an '@' terminating a
- value for a key type which does not require a
- trailing ';'. */
- pat = rcsbuf->ptrend - 1;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *strp;
- if (vlen == 0)
- *strp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a
- @-delimited string, or `:'). Store the result in WORDP. If a
- `;' is reached without reading any text, the result is NULL. */
-
-static int
-rcsbuf_getword (rcsbuf, wordp)
- struct rcsbuffer *rcsbuf;
- char **wordp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* If we have reached `;', there is no value. */
- if (c == ';')
- {
- *wordp = NULL;
- *ptr++ = '\0';
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 0;
- return 1;
- }
-
- /* PTR now points to the start of a value. Find out whether it is
- a num, an id, a string or a colon. */
- if (c == ':')
- {
- *wordp = ptr++;
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 1;
- return 1;
- }
-
- if (c == '@')
- {
- char *pat;
- size_t vlen;
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *wordp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp);
- if (pat == NULL)
- {
- /* EOF here is OK; it just means that the last
- character of the file was an '@' terminating a
- value for a key type which does not require a
- trailing ';'. */
- pat = rcsbuf->ptrend - 1;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *wordp;
- if (vlen == 0)
- *wordp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
- }
-
- /* C is neither `:', `;' nor `@', so it should be the start of a num
- or an id. Make sure it is not another special character. */
- if (c == '$' || c == '.' || c == ',')
- {
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- }
-
- *wordp = ptr;
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Legitimate ID characters are digits, dots and any `graphic
- printing character that is not a special.' This test ought
- to do the trick. */
- c = *ptr;
- if (isprint ((unsigned char) c) &&
- c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
- {
- ++ptr;
- continue;
- }
- break;
- }
-
- /* PTR points to the last non-id character in this word, and C is
- the character in its memory cell. Check to make sure that it
- is a legitimate word delimiter -- whitespace or semicolon. */
- if (c == ';' || my_whitespace (c))
- {
- rcsbuf->vlen = ptr - *wordp;
- rcsbuf->ptr = ptr;
- return 1;
- }
-
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- /* Shut up compiler warnings. */
- return 0;
-
-#undef my_whitespace
-}
-
/* Read an RCS revision number from an RCS file. This sets *REVP to
point to the revision number; it will point to space that is
managed by the rcsbuf functions, and is only good until the next
@@ -1988,6 +1510,8 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
koff = *keyp - rcsbuf_buffer;
if (valp != NULL && *valp != NULL)
voff = *valp - rcsbuf_buffer;
+ koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
+ voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
rcsbuf_buffer_size + RCSBUF_BUFSIZE);
@@ -2013,6 +1537,16 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
return ptr;
}
+/* Test whether the last value returned by rcsbuf_getkey is a composite
+ value or not. */
+
+static int
+rcsbuf_valcmp (rcsbuf)
+ struct rcsbuffer *rcsbuf;
+{
+ return rcsbuf->at_string && rcsbuf->embedded_at < 0;
+}
+
/* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
returning the memory buffer. Polish the value like
rcsbuf_valpolish, q.v. */
@@ -2036,7 +1570,7 @@ rcsbuf_valcopy (rcsbuf, val, polish, lenp)
}
vlen = rcsbuf->vlen;
- embedded_at = rcsbuf->embedded_at;
+ embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
ret = xmalloc (vlen - embedded_at + 1);
@@ -2143,6 +1677,7 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
orig_to = to;
embedded_at = rcsbuf->embedded_at;
+ assert (embedded_at > 0);
if (lenp != NULL)
*lenp = len - embedded_at;
@@ -2191,6 +1726,112 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
}
}
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
+/* Copy the next word from the value VALP returned by rcsbuf_getkey into a
+ memory buffer, updating VALP and returning the memory buffer. Return
+ NULL when there are no more words. */
+
+static char *
+rcsbuf_valword (rcsbuf, valp)
+ struct rcsbuffer *rcsbuf;
+ char **valp;
+{
+ register const char * const my_spacetab = spacetab;
+ register char *ptr, *pat;
+ char c;
+
+#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
+
+ if (*valp == NULL)
+ return NULL;
+
+ for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
+ if (*ptr == '\0')
+ {
+ assert (ptr - *valp == rcsbuf->vlen);
+ *valp = NULL;
+ rcsbuf->vlen = 0;
+ return NULL;
+ }
+
+ /* PTR now points to the start of a value. Find out whether it is
+ a num, an id, a string or a colon. */
+ c = *ptr;
+ if (c == ':')
+ {
+ rcsbuf->vlen -= ++ptr - *valp;
+ *valp = ptr;
+ return xstrdup (":");
+ }
+
+ if (c == '@')
+ {
+ int embedded_at = 0;
+ size_t vlen;
+
+ pat = ++ptr;
+ while ((pat = strchr (pat, '@')) != NULL)
+ {
+ if (pat[1] != '@')
+ break;
+ ++embedded_at;
+ pat += 2;
+ }
+
+ /* Here PAT points to the final '@' in the string. */
+ *pat++ = '\0';
+ assert (rcsbuf->at_string);
+ vlen = rcsbuf->vlen - (pat - *valp);
+ rcsbuf->vlen = pat - ptr - 1;
+ rcsbuf->embedded_at = embedded_at;
+ ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
+ *valp = pat;
+ rcsbuf->vlen = vlen;
+ if (strchr (pat, '@') == NULL)
+ rcsbuf->at_string = 0;
+ else
+ rcsbuf->embedded_at = -1;
+ return ptr;
+ }
+
+ /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
+ or an id. Make sure it is not another special character. */
+ if (c == '$' || c == '.' || c == ',')
+ {
+ error (1, 0, "illegal special character in RCS field in %s",
+ rcsbuf->filename);
+ }
+
+ pat = ptr;
+ while (1)
+ {
+ /* Legitimate ID characters are digits, dots and any `graphic
+ printing character that is not a special.' This test ought
+ to do the trick. */
+ c = *++pat;
+ if (!isprint ((unsigned char) c) ||
+ c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
+ break;
+ }
+
+ /* PAT points to the last non-id character in this word, and C is
+ the character in its memory cell. Check to make sure that it
+ is a legitimate word delimiter -- whitespace or end. */
+ if (c != '\0' && !my_whitespace (c))
+ error (1, 0, "illegal special character in RCS field in %s",
+ rcsbuf->filename);
+
+ *pat = '\0';
+ rcsbuf->vlen -= pat - *valp;
+ *valp = pat;
+ return xstrdup (ptr);
+
+#undef my_whitespace
+}
+
+#endif
+
/* Return the current position of an rcsbuf. */
static unsigned long
@@ -2880,8 +2521,8 @@ RCS_nodeisbranch (rcs, rev)
return (1);
}
free (magic);
- free (version);
}
+ free (version);
return (0);
}
@@ -2930,8 +2571,8 @@ RCS_whatbranch (rcs, rev)
return (magic);
}
free (magic);
- free (version);
}
+ free (version);
return ((char *) NULL);
}
@@ -4102,6 +3743,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
uses for ci -k. */
if (kw == KEYWORD_LOG
&& (sizeof "checked in with -k by " <= loglen
+ || log == NULL
|| strncmp (log, "checked in with -k by ",
sizeof "checked in with -k by " - 1) != 0))
{
@@ -4120,6 +3762,10 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
if (expand != KFLAG_V)
++s;
+ /* CVS never has empty log messages, but old RCS files might. */
+ if (log == NULL)
+ log = "";
+
/* Find the start of the line. */
start = srch;
while (start > buf && start[-1] != '\n')
@@ -4690,6 +4336,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
#ifdef PRESERVE_PERMISSIONS_SUPPORT
else if (special_file)
{
+#ifdef HAVE_MKNOD
char *dest;
/* Can send either to WORKFILE or to SOUT, as long as SOUT is
@@ -4710,6 +4357,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (mknod (dest, special_file, devnum) < 0)
error (1, errno, "could not create special file %s",
dest);
+#else
+ error (1, 0,
+"cannot create %s: unable to create special files on this system",
+workfile);
+#endif
}
#endif
else
@@ -5073,8 +4725,10 @@ RCS_addbranch (rcs, branch)
if (nodep == NULL)
{
error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
+ free (branchpoint);
return NULL;
}
+ free (branchpoint);
branchnode = (RCSVers *) nodep->data;
/* If BRANCH was a full branch number, make sure it is higher than MAX. */
@@ -5276,6 +4930,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (S_ISLNK (sb.st_mode))
{
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("symlink");
np->data = xreadlink (workfile);
addnode (delta->other_delta, np);
@@ -5284,18 +4939,21 @@ RCS_checkin (rcs, workfile, message, rev, flags)
{
(void) sprintf (buf, "%u", sb.st_uid);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("owner");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
(void) sprintf (buf, "%u", sb.st_gid);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("group");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
(void) sprintf (buf, "%o", sb.st_mode & 07777);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("permissions");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
@@ -5306,7 +4964,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
case S_IFREG: break;
case S_IFCHR:
case S_IFBLK:
+#ifdef HAVE_ST_RDEV
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("special");
sprintf (buf, "%s %lu",
((sb.st_mode & S_IFMT) == S_IFCHR
@@ -5314,6 +4974,11 @@ RCS_checkin (rcs, workfile, message, rev, flags)
(unsigned long) sb.st_rdev);
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
+#else
+ error (0, 0,
+"can't preserve %s: unable to save device files on this system",
+workfile);
+#endif
break;
default:
@@ -5358,8 +5023,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
delta->version = xstrdup (newrev);
nodep = getnode();
nodep->type = RCSVERS;
- nodep->key = xstrdup (newrev);
+ nodep->delproc = rcsvers_delproc;
nodep->data = (char *) delta;
+ nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
dtext->version = xstrdup (newrev);
@@ -5393,7 +5059,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
error (1, errno, "cannot ftell for %s", rcs->path);
putdeltatext (fout, dtext);
rcs_internal_unlockfile (fout, rcs->path);
- freedeltatext (dtext);
if ((flags & RCS_FLAGS_KEEPFILE) == 0)
{
@@ -5405,7 +5070,8 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (!checkin_quiet)
cvs_output ("done\n", 5);
- return 0;
+ status = 0;
+ goto checkin_done;
}
/* Derive a new revision number. From the `ci' man page:
@@ -5501,6 +5167,13 @@ RCS_checkin (rcs, workfile, message, rev, flags)
goto checkin_done;
}
delta->version = RCS_addbranch (rcs, branch);
+ if (!delta->version)
+ {
+ free (branch);
+ free (newrev);
+ status = 1;
+ goto checkin_done;
+ }
adding_branch = 1;
p = strrchr (branch, '.');
*p = '\0';
@@ -5725,8 +5398,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
rcs->versions = getlist();
nodep = getnode();
nodep->type = RCSVERS;
- nodep->key = xstrdup (delta->version);
+ nodep->delproc = rcsvers_delproc;
nodep->data = (char *) delta;
+ nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
/* Write the new RCS file, inserting the new delta at COMMITPT. */
@@ -5749,8 +5423,10 @@ RCS_checkin (rcs, workfile, message, rev, flags)
}
if (unlink_file (tmpfile) < 0)
error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
if (unlink_file (changefile) < 0)
error (0, errno, "cannot remove %s", changefile);
+ free (changefile);
if (!checkin_quiet)
cvs_output ("done\n", 5);
@@ -5833,6 +5509,7 @@ RCS_cmp_file (rcs, rev, options, filename)
retcode = xcmp (tmp, filename);
if (CVS_UNLINK (tmp) < 0)
error (0, errno, "cannot remove %s", tmp);
+ free (tmp);
return retcode;
}
else
@@ -6193,17 +5870,14 @@ RCS_unlock (rcs, rev, unlock_quiet)
lock = NULL;
for (p = locks->list->next; p != locks->list; p = p->next)
{
- if (STREQ (p->data, user))
+ if (lock != NULL)
{
- if (lock != NULL)
- {
- if (!unlock_quiet)
- error (0, 0, "\
+ if (!unlock_quiet)
+ error (0, 0, "\
%s: multiple revisions locked by %s; please specify one", rcs->path, user);
- return 1;
- }
- lock = p;
+ return 1;
}
+ lock = p;
}
if (lock == NULL)
return 0; /* no lock found, ergo nothing to do */
@@ -6283,6 +5957,7 @@ RCS_addaccess (rcs, user)
return;
}
}
+ free (access);
rcs->access = (char *) xrealloc
(rcs->access, strlen (rcs->access) + strlen (user) + 2);
strcat (rcs->access, " ");
@@ -6306,13 +5981,19 @@ RCS_delaccess (rcs, user)
if (rcs->access == NULL)
return;
+ if (user == NULL)
+ {
+ free (rcs->access);
+ rcs->access = NULL;
+ return;
+ }
+
p = rcs->access;
ulen = strlen (user);
while (p != NULL)
{
- if (p[ulen] == '\0' || p[ulen] == ' ')
- if (strncmp (p, user, ulen) == 0)
- break;
+ if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
+ break;
p = strchr (p, ' ');
if (p != NULL)
++p;
@@ -7711,7 +7392,7 @@ getdelta (rcsbuf, rcsfile, keyp, valp)
char **valp;
{
RCSVers *vnode;
- char *key, *value, *keybuf, *valbuf, *cp;
+ char *key, *value, *cp;
Node *kv;
/* Get revision number if it wasn't passed in. This uses
@@ -7829,81 +7510,32 @@ unable to parse %s; `state' not in the expected place", rcsfile);
*/
while (1)
{
- int len;
- size_t valbuflen;
-
- key = NULL;
-
- if (! rcsbuf_getid (rcsbuf, &keybuf))
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
error (1, 0, "unexpected end of file reading %s", rcsfile);
- /* rcsbuf_getid did not terminate the key, so copy it to new space. */
- len = rcsbuf->ptr - keybuf;
- key = (char *) xmalloc (sizeof(char) * (len + 1));
- strncpy (key, keybuf, len);
- key[len] = '\0';
-
- /* The `desc' keyword has only a single string value, with no
- trailing semicolon, so it must be handled specially. */
- if (STREQ (key, RCSDESC))
- {
- (void) rcsbuf_getstring (rcsbuf, &valbuf);
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
+ /* The `desc' keyword is the end of the deltas. */
+ if (strcmp (key, RCSDESC) == 0)
break;
- }
#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
/* The `hardlinks' value is a group of words, which must
be parsed separately and added as a list to vnode->hardlinks. */
- if (STREQ (key, "hardlinks"))
+ if (strcmp (key, "hardlinks") == 0)
{
- Node *n;
+ char *word;
vnode->hardlinks = getlist();
- while (1)
+ while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
{
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
- n = getnode();
- n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL);
+ Node *n = getnode();
+ n->key = word;
addnode (vnode->hardlinks, n);
}
continue;
}
#endif
- /* Get the value. */
- value = NULL;
- while (1)
- {
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
-
- /* Copy valbuf to new space so we can polish it, then
- append it to value. */
-
- if (value == NULL)
- {
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- }
- else
- {
- char *temp_value;
-
- temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- len = strlen (value);
- value = (char *) xrealloc
- (value, sizeof(char) * (len + valbuflen + 2));
- value[len] = ' ';
- strcpy (value + len + 1, temp_value);
- free (temp_value);
- }
- }
-
/* Enable use of repositories created by certain obsolete
versions of CVS. This code should remain indefinately;
there is no procedure for converting old repositories, and
@@ -7932,9 +7564,10 @@ unable to parse %s; `state' not in the expected place", rcsfile);
if (vnode->other_delta == NULL)
vnode->other_delta = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
- kv->key = key;
- kv->data = value;
+ kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (vnode->other_delta, kv) != 0)
{
/* Complaining about duplicate keys in newphrases seems
@@ -8019,9 +7652,10 @@ RCS_getdeltatext (rcs, fp, rcsbuf)
break;
p = getnode();
- p->type = RCSFIELD;
+ p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
p->key = xstrdup (key);
- p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
+ p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (d->other, p) < 0)
{
error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
@@ -8102,8 +7736,8 @@ putrcsfield_proc (node, vfp)
A case where we are wrong in a much more clear-cut way is that
we let through non-graphic characters such as whitespace and
control characters. */
- int n = strcspn (node->data, "$,.:;@");
- if (node->data[n] == 0)
+
+ if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
fputs (node->data, fp);
else
{
@@ -8264,7 +7898,13 @@ RCS_putdtree (rcs, rev, fp)
/* Find the delta node for this revision. */
p = findnode (rcs->versions, rev);
- assert (p != NULL);
+ if (p == NULL)
+ {
+ error (1, 0,
+ "error parsing repository file %s, file may be corrupt.",
+ rcs->path);
+ }
+
versp = (RCSVers *) p->data;
/* Print the delta node and recurse on its `next' node. This prints
@@ -8385,6 +8025,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
/* If this revision has been outdated, just skip it. */
if (dadmin->outdated)
{
+ freedeltatext (dtext);
--actions;
continue;
}
@@ -8504,7 +8145,7 @@ count_delta_actions (np, ignore)
/*
* Clean up temporary files
*/
-static RETSIGTYPE
+RETSIGTYPE
rcs_cleanup ()
{
/* Note that the checks for existence_error are because we are
@@ -8518,11 +8159,18 @@ rcs_cleanup ()
of a just-created file) reentrancy won't be an issue. */
if (rcs_lockfile != NULL)
{
- if (unlink_file (rcs_lockfile) < 0
+ char *tmp = rcs_lockfile;
+ rcs_lockfile = NULL;
+ if (rcs_lockfd >= 0)
+ {
+ if (close (rcs_lockfd) != 0)
+ error (0, errno, "error closing lock file %s", tmp);
+ rcs_lockfd = -1;
+ }
+ if (unlink_file (tmp) < 0
&& !existence_error (errno))
- error (0, errno, "cannot remove %s", rcs_lockfile);
+ error (0, errno, "cannot remove %s", tmp);
}
- rcs_lockfile = NULL;
}
/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
@@ -8556,7 +8204,6 @@ static FILE *
rcs_internal_lockfile (rcsfile)
char *rcsfile;
{
- int fd;
struct stat rstat;
FILE *fp;
static int first_call = 1;
@@ -8565,6 +8212,9 @@ rcs_internal_lockfile (rcsfile)
{
first_call = 0;
/* clean up if we get a signal */
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, rcs_cleanup);
+#endif
#ifdef SIGHUP
(void) SIG_register (SIGHUP, rcs_cleanup);
#endif
@@ -8584,6 +8234,7 @@ rcs_internal_lockfile (rcsfile)
/* Get the lock file name: `,file,' for RCS file `file,v'. */
assert (rcs_lockfile == NULL);
+ assert (rcs_lockfd < 0);
rcs_lockfile = rcs_lockfilename (rcsfile);
/* Use the existing RCS file mode, or read-only if this is a new
@@ -8610,11 +8261,11 @@ rcs_internal_lockfile (rcsfile)
rely on O_EXCL these days. This might be true for unix (I
don't really know), but I am still pretty skeptical in the case
of the non-unix systems. */
- fd = open (rcs_lockfile,
- OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
- S_IRUSR | S_IRGRP | S_IROTH);
+ rcs_lockfd = open (rcs_lockfile,
+ OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
- if (fd < 0)
+ if (rcs_lockfd < 0)
{
error (1, errno, "could not open lock file `%s'", rcs_lockfile);
}
@@ -8623,10 +8274,10 @@ rcs_internal_lockfile (rcsfile)
/* Because we change the modes later, we don't worry about
this in the non-HAVE_FCHMOD case. */
#ifdef HAVE_FCHMOD
- if (fchmod (fd, rstat.st_mode) < 0)
+ if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
error (1, errno, "cannot change mode for %s", rcs_lockfile);
#endif
- fp = fdopen (fd, FOPEN_BINARY_WRITE);
+ fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
if (fp == NULL)
error (1, errno, "cannot fdopen %s", rcs_lockfile);
@@ -8639,6 +8290,7 @@ rcs_internal_unlockfile (fp, rcsfile)
char *rcsfile;
{
assert (rcs_lockfile != NULL);
+ assert (rcs_lockfd >= 0);
/* Abort if we could not write everything successfully to LOCKFILE.
This is not a great error-handling mechanism, but should prevent
@@ -8654,6 +8306,7 @@ rcs_internal_unlockfile (fp, rcsfile)
error (1, 0, "error writing to lock file %s", rcs_lockfile);
if (fclose (fp) == EOF)
error (1, errno, "error closing lock file %s", rcs_lockfile);
+ rcs_lockfd = -1;
rename_file (rcs_lockfile, rcsfile);
@@ -8747,6 +8400,22 @@ RCS_rewrite (rcs, newdtext, insertpt)
rcs_internal_unlockfile (fout, rcs->path);
}
+/* Abandon changes to an RCS file. */
+
+void
+RCS_abandon (rcs)
+ RCSNode *rcs;
+{
+ free_rcsnode_contents (rcs);
+ rcs->symbols_data = NULL;
+ rcs->expand = NULL;
+ rcs->access = NULL;
+ rcs->locks_data = NULL;
+ rcs->comment = NULL;
+ rcs->desc = NULL;
+ rcs->flags |= PARTIAL;
+}
+
/* Annotate command. In rcs.c for historical reasons (from back when
what is now RCS_deltas was part of annotate_fileproc). */
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index 7aee90a..397488e 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -10,8 +10,10 @@
* $FreeBSD$
*/
-/* String which indicates a conflict if it occurs at the start of a line. */
-#define RCS_MERGE_PAT ">>>>>>> "
+/* Strings which indicate a conflict if they occur at the start of a line. */
+#define RCS_MERGE_PAT_1 "<<<<<<< "
+#define RCS_MERGE_PAT_2 "=======\n"
+#define RCS_MERGE_PAT_3 ">>>>>>> "
#define RCSEXT ",v"
#define RCSPAT "*,v"
@@ -229,7 +231,9 @@ int RCS_delete_revs PROTO ((RCSNode *, char *, char *, int));
void RCS_addaccess PROTO ((RCSNode *, char *));
void RCS_delaccess PROTO ((RCSNode *, char *));
char *RCS_getaccess PROTO ((RCSNode *));
+RETSIGTYPE rcs_cleanup PROTO ((void));
void RCS_rewrite PROTO ((RCSNode *, Deltatext *, char *));
+void RCS_abandon PROTO ((RCSNode *));
int rcs_change_text PROTO ((const char *, char *, size_t, const char *,
size_t, char **, size_t *));
void RCS_setincexc PROTO ((const char *arg));
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index 209d324..09e1cad 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -174,6 +174,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
seems to be handled somewhere (else) but why should
it be a separate case? Needs investigation... */
just_subdirs = 1;
+ free (root);
}
#endif
@@ -591,7 +592,7 @@ do_recursion (frame)
/* Add it to our list. */
Node *n = getnode ();
- n->type = UNKNOWN;
+ n->type = NT_UNKNOWN;
n->key = xstrdup (this_root);
if (addnode (root_directories, n))
@@ -1016,7 +1017,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
/* Add it to our list. */
Node *n = getnode ();
- n->type = UNKNOWN;
+ n->type = NT_UNKNOWN;
n->key = xstrdup (this_root);
if (addnode (root_directories, n))
@@ -1133,6 +1134,7 @@ addfile (listp, dir, file)
char *file;
{
Node *n;
+ List *fl;
/* add this dir. */
addlist (listp, dir);
@@ -1145,7 +1147,9 @@ addfile (listp, dir, file)
}
n->type = DIRS;
- addlist ((List **) &n->data, file);
+ fl = (List *) n->data;
+ addlist (&fl, file);
+ n->data = (char *) fl;
return;
}
@@ -1205,6 +1209,7 @@ unroll_files_proc (p, closure)
}
dirlist = save_dirlist;
- filelist = NULL;
+ if (filelist)
+ dellist (&filelist);
return(err);
}
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index 63fef8c..a53dc79 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -187,6 +187,7 @@ static int fd_buffer_input PROTO((void *, char *, int, int, int *));
static int fd_buffer_output PROTO((void *, const char *, int, int *));
static int fd_buffer_flush PROTO((void *));
static int fd_buffer_block PROTO((void *, int));
+static int fd_buffer_shutdown PROTO((void *));
/* Initialize a buffer built on a file descriptor. FD is the file
descriptor. INPUT is nonzero if this is for input, zero if this is
@@ -208,7 +209,7 @@ fd_buffer_initialize (fd, input, memory)
input ? NULL : fd_buffer_output,
input ? NULL : fd_buffer_flush,
fd_buffer_block,
- (int (*) PROTO((void *))) NULL,
+ fd_buffer_shutdown,
memory,
n);
}
@@ -345,6 +346,16 @@ fd_buffer_block (closure, block)
return 0;
}
+/* The buffer shutdown function for a buffer built on a file descriptor. */
+
+static int
+fd_buffer_shutdown (closure)
+ void *closure;
+{
+ free (closure);
+ return 0;
+}
+
/* Populate all of the directories between BASE_DIR and its relative
subdirectory DIR with CVSADM directories. Return 0 for success or
errno value. */
@@ -742,8 +753,6 @@ serve_root (arg)
{
char *env;
char *path;
- int save_errno;
- char *arg_dup;
if (error_pending()) return;
@@ -785,14 +794,7 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
}
}
#endif
- arg_dup = malloc (strlen (arg) + 1);
- if (arg_dup == NULL)
- {
- pending_error = ENOMEM;
- return;
- }
- strcpy (arg_dup, arg);
- set_local_cvsroot (arg_dup);
+ set_local_cvsroot (arg);
/* For pserver, this will already have happened, and the call will do
nothing. But for rsh, we need to do it now. */
@@ -803,7 +805,6 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
path = malloc (strlen (CVSroot_directory)
+ sizeof (CVSROOTADM)
- + sizeof (CVSROOTADM_HISTORY)
+ 10);
if (path == NULL)
{
@@ -813,23 +814,11 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
(void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
- save_errno = errno;
- pending_error_text = malloc (80 + strlen (path));
- if (pending_error_text != NULL)
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (path)))
sprintf (pending_error_text, "E Cannot access %s", path);
pending_error = save_errno;
}
- (void) strcat (path, "/");
- (void) strcat (path, CVSROOTADM_HISTORY);
- if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
- {
- save_errno = errno;
- pending_error_text = malloc (80 + strlen (path));
- if (pending_error_text != NULL)
- sprintf (pending_error_text, "E \
-Sorry, you don't have read/write access to the history file %s", path);
- pending_error = save_errno;
- }
free (path);
#ifdef HAVE_PUTENV
@@ -1043,9 +1032,9 @@ dirswitch (dir, repos)
if (status != 0
&& status != EEXIST)
{
- pending_error = status;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot mkdir %s", dir_name);
+ pending_error = status;
return;
}
@@ -1058,17 +1047,18 @@ dirswitch (dir, repos)
status = create_adm_p (server_temp_dir, dir);
if (status != 0)
{
- pending_error = status;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot create_adm_p %s", dir_name);
+ pending_error = status;
return;
}
if ( CVS_CHDIR (dir_name) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot change to %s", dir_name);
+ pending_error = save_errno;
return;
}
/*
@@ -1077,10 +1067,14 @@ dirswitch (dir, repos)
*/
if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM)))
+ sprintf (pending_error_text,
+ "E cannot mkdir %s/%s", dir_name, CVSADM);
+ pending_error = save_errno;
return;
}
-
+
/* The following will overwrite the contents of CVSADM_REP. This
is the correct behavior -- mkdir_p may have written a
placeholder value to this file and we need to insert the
@@ -1089,12 +1083,20 @@ dirswitch (dir, repos)
f = CVS_FOPEN (CVSADM_REP, "w");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E cannot open %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s", repos) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
@@ -1107,20 +1109,32 @@ dirswitch (dir, repos)
{
if (fprintf (f, "/.") < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
}
if (fprintf (f, "\n") < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error closing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
return;
}
/* We open in append mode because we don't want to clobber an
@@ -1128,16 +1142,18 @@ dirswitch (dir, repos)
f = CVS_FOPEN (CVSADM_ENT, "a");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
return;
}
}
@@ -1146,10 +1162,7 @@ static void
serve_repository (arg)
char *arg;
{
- pending_error_text = malloc (80);
- if (pending_error_text == NULL)
- pending_error = ENOMEM;
- else
+ if (alloc_pending (80))
strcpy (pending_error_text,
"E Repository request is obsolete; aborted");
return;
@@ -1165,9 +1178,8 @@ serve_directory (arg)
status = buf_read_line (buf_from_net, &repos, (int *) NULL);
if (status == 0)
{
- if (outside_root (repos))
- return;
- dirswitch (arg, repos);
+ if (!outside_root (repos))
+ dirswitch (arg, repos);
free (repos);
}
else if (status == -2)
@@ -1206,16 +1218,18 @@ serve_static_directory (arg)
f = CVS_FOPEN (CVSADM_ENTSTAT, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
return;
}
}
@@ -1231,23 +1245,26 @@ serve_sticky (arg)
f = CVS_FOPEN (CVSADM_TAG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
}
@@ -1306,10 +1323,10 @@ receive_partial_file (size, file)
nwrote = write (file, data, nread);
if (nwrote < 0)
{
- pending_error_text = malloc (40);
- if (pending_error_text != NULL)
- sprintf (pending_error_text, "E unable to write");
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (40))
+ strcpy (pending_error_text, "E unable to write");
+ pending_error = save_errno;
/* Read and discard the file data. */
while (size > 0)
@@ -1345,10 +1362,10 @@ receive_file (size, file, gzipped)
fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text, "E cannot open %s", arg);
- pending_error = errno;
+ pending_error = save_errno;
return;
}
@@ -1414,7 +1431,7 @@ receive_file (size, file, gzipped)
goto out;
}
- if (gunzip_and_write (fd, file, filebuf, size))
+ if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
{
if (alloc_pending (80))
sprintf (pending_error_text,
@@ -1440,10 +1457,10 @@ receive_file (size, file, gzipped)
out:
if (close (fd) < 0 && !error_pending ())
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text, "E cannot close %s", arg);
- pending_error = errno;
+ pending_error = save_errno;
return;
}
}
@@ -1522,10 +1539,11 @@ serve_modified (arg)
{
sprintf (pending_error_text,
"E error reading size for %s", arg);
- pending_error = errno;
+ pending_error = status;
}
}
}
+ free (mode_text);
return;
}
if (size_text[0] == 'z')
@@ -1550,16 +1568,24 @@ serve_modified (arg)
return;
size -= nread;
}
+ free (mode_text);
return;
}
if (outside_dir (arg))
+ {
+ free (mode_text);
return;
+ }
if (size >= 0)
{
receive_file (size, arg, gzipped);
- if (error_pending ()) return;
+ if (error_pending ())
+ {
+ free (mode_text);
+ return;
+ }
}
if (checkin_time_valid)
@@ -1570,9 +1596,11 @@ serve_modified (arg)
t.modtime = t.actime = checkin_time;
if (utime (arg, &t) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (arg)))
sprintf (pending_error_text, "E cannot utime %s", arg);
+ pending_error = save_errno;
+ free (mode_text);
return;
}
checkin_time_valid = 0;
@@ -1583,8 +1611,7 @@ serve_modified (arg)
free (mode_text);
if (status)
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text,
"E cannot change mode for %s", arg);
pending_error = status;
@@ -1859,9 +1886,10 @@ server_write_entries ()
f = CVS_FOPEN (CVSADM_ENT, "a");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
for (p = entries; p != NULL;)
@@ -1870,10 +1898,11 @@ server_write_entries ()
{
if (fprintf (f, "%s\n", p->entry) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen(CVSADM_ENT)))
sprintf (pending_error_text,
"E cannot write to %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
free (p->entry);
@@ -1884,9 +1913,10 @@ server_write_entries ()
entries = NULL;
if (f != NULL && fclose (f) == EOF && !error_pending ())
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
@@ -1918,8 +1948,8 @@ static void
serve_notify (arg)
char *arg;
{
- struct notify_note *new;
- char *data;
+ struct notify_note *new = NULL;
+ char *data = NULL;
int status;
if (error_pending ()) return;
@@ -1927,27 +1957,26 @@ serve_notify (arg)
if (outside_dir (arg))
return;
+ if (dir_name == NULL)
+ goto error;
+
new = (struct notify_note *) malloc (sizeof (struct notify_note));
if (new == NULL)
{
pending_error = ENOMEM;
return;
}
- if (dir_name == NULL)
- goto error;
new->dir = malloc (strlen (dir_name) + 1);
- if (new->dir == NULL)
- {
- pending_error = ENOMEM;
- return;
- }
- strcpy (new->dir, dir_name);
new->filename = malloc (strlen (arg) + 1);
- if (new->filename == NULL)
+ if (new->dir == NULL || new->filename == NULL)
{
pending_error = ENOMEM;
+ if (new->dir != NULL)
+ free (new->dir);
+ free (new);
return;
}
+ strcpy (new->dir, dir_name);
strcpy (new->filename, arg);
status = buf_read_line (buf_from_net, &data, (int *) NULL);
@@ -1973,6 +2002,9 @@ serve_notify (arg)
}
}
}
+ free (new->filename);
+ free (new->dir);
+ free (new);
}
else
{
@@ -2020,11 +2052,18 @@ serve_notify (arg)
}
return;
error:
- pending_error_text = malloc (80);
- if (pending_error_text)
+ pending_error = 0;
+ if (alloc_pending (80))
strcpy (pending_error_text,
"E Protocol error; misformed Notify request");
- pending_error = 0;
+ if (data != NULL)
+ free (data);
+ if (new != NULL)
+ {
+ free (new->filename);
+ free (new->dir);
+ free (new);
+ }
return;
}
@@ -2067,6 +2106,7 @@ server_notify ()
buf_append_char (buf_to_net, '/');
buf_output0 (buf_to_net, notify_list->filename);
buf_append_char (buf_to_net, '\n');
+ free (repos);
p = notify_list->next;
free (notify_list->filename);
@@ -2654,22 +2694,26 @@ error \n");
if (pipe (stdout_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
if (pipe (stderr_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
if (pipe (protocol_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
#ifdef SERVER_FLOWCONTROL
if (pipe (flowcontrol_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
@@ -2680,6 +2724,7 @@ error \n");
dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY);
if (dev_null_fd < 0)
{
+ buf_output0 (buf_to_net, "E open /dev/null failed\n");
print_error (errno);
goto error_exit;
}
@@ -2707,6 +2752,7 @@ error \n");
command_pid = fork ();
if (command_pid < 0)
{
+ buf_output0 (buf_to_net, "E fork failed\n");
print_error (errno);
goto error_exit;
}
@@ -2740,8 +2786,11 @@ error \n");
error (1, errno, "can't set up pipes");
if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
error (1, errno, "can't set up pipes");
+ close (dev_null_fd);
close (stdout_pipe[0]);
+ close (stdout_pipe[1]);
close (stderr_pipe[0]);
+ close (stderr_pipe[1]);
close (protocol_pipe[0]);
#ifdef SERVER_FLOWCONTROL
close (flowcontrol_pipe[1]);
@@ -2776,6 +2825,7 @@ error \n");
* When we exit, that will close the pipes, giving an EOF to
* the parent.
*/
+ buf_free (protocol);
exit (exitstatus);
}
@@ -2832,6 +2882,7 @@ error \n");
if (close (stdout_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2839,6 +2890,7 @@ error \n");
if (close (stderr_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2846,6 +2898,7 @@ error \n");
if (close (protocol_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2854,6 +2907,7 @@ error \n");
#ifdef SERVER_FLOWCONTROL
if (close (flowcontrol_pipe[0]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2862,6 +2916,7 @@ error \n");
if (close (dev_null_fd) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2929,6 +2984,7 @@ error \n");
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
goto error_exit;
}
@@ -2940,48 +2996,6 @@ error \n");
buf_send_output (buf_to_net);
}
- if (stdout_pipe[0] >= 0
- && (FD_ISSET (stdout_pipe[0], &readfds)))
- {
- int status;
-
- status = buf_input_data (stdoutbuf, (int *) NULL);
-
- buf_copy_lines (buf_to_net, stdoutbuf, 'M');
-
- if (status == -1)
- stdout_pipe[0] = -1;
- else if (status > 0)
- {
- print_error (status);
- goto error_exit;
- }
-
- /* What should we do with errors? syslog() them? */
- buf_send_output (buf_to_net);
- }
-
- if (stderr_pipe[0] >= 0
- && (FD_ISSET (stderr_pipe[0], &readfds)))
- {
- int status;
-
- status = buf_input_data (stderrbuf, (int *) NULL);
-
- buf_copy_lines (buf_to_net, stderrbuf, 'E');
-
- if (status == -1)
- stderr_pipe[0] = -1;
- else if (status > 0)
- {
- print_error (status);
- goto error_exit;
- }
-
- /* What should we do with errors? syslog() them? */
- buf_send_output (buf_to_net);
- }
-
if (protocol_pipe[0] >= 0
&& (FD_ISSET (protocol_pipe[0], &readfds)))
{
@@ -2992,9 +3006,13 @@ error \n");
status = buf_input_data (protocol_inbuf, &count_read);
if (status == -1)
+ {
+ close (protocol_pipe[0]);
protocol_pipe[0] = -1;
+ }
else if (status > 0)
{
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
print_error (status);
goto error_exit;
}
@@ -3031,6 +3049,56 @@ error \n");
}
}
}
+
+ if (stdout_pipe[0] >= 0
+ && (FD_ISSET (stdout_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stdoutbuf, (int *) NULL);
+
+ buf_copy_lines (buf_to_net, stdoutbuf, 'M');
+
+ if (status == -1)
+ {
+ close (stdout_pipe[0]);
+ stdout_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
+
+ if (stderr_pipe[0] >= 0
+ && (FD_ISSET (stderr_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stderrbuf, (int *) NULL);
+
+ buf_copy_lines (buf_to_net, stderrbuf, 'E');
+
+ if (status == -1)
+ {
+ close (stderr_pipe[0]);
+ stderr_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
}
/*
@@ -3052,6 +3120,11 @@ error \n");
buf_output0 (buf_to_net,
"E Protocol error: uncounted data discarded\n");
+#ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[1]);
+ flowcontrol_pipe[1] = -1;
+#endif /* SERVER_FLOWCONTROL */
+
errs = 0;
while (command_pid > 0)
@@ -3106,6 +3179,12 @@ E CVS locks may need cleaning up.\n");
*/
set_block (buf_to_net);
buf_flush (buf_to_net, 1);
+ buf_shutdown (protocol_inbuf);
+ buf_free (protocol_inbuf);
+ buf_shutdown (stderrbuf);
+ buf_free (stderrbuf);
+ buf_shutdown (stdoutbuf);
+ buf_free (stdoutbuf);
}
if (errs)
@@ -3136,6 +3215,10 @@ E CVS locks may need cleaning up.\n");
close (stderr_pipe[1]);
close (stdout_pipe[0]);
close (stdout_pipe[1]);
+#ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[0]);
+ close (flowcontrol_pipe[1]);
+#endif /* SERVER_FLOWCONTROL */
free_args_and_return:
/* Now free the arguments. */
@@ -3191,6 +3274,7 @@ server_pause_check()
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
return;
}
@@ -3631,23 +3715,29 @@ serve_editors (arg)
do_cvs_command ("editors", editors);
}
-static int noop PROTO ((int, char **));
+static void serve_noop PROTO ((char *));
-static int
-noop (argc, argv)
- int argc;
- char **argv;
+static void
+serve_noop (arg)
+ char *arg;
{
- return 0;
+
+ server_write_entries ();
+ if (!print_pending_error ())
+ {
+ (void) server_notify ();
+ buf_output0 (buf_to_net, "ok\n");
+ }
+ buf_flush (buf_to_net, 1);
}
-static void serve_noop PROTO ((char *));
+static void serve_version PROTO ((char *));
static void
-serve_noop (arg)
+serve_version (arg)
char *arg;
{
- do_cvs_command ("noop", noop);
+ do_cvs_command ("version", version);
}
static void serve_init PROTO ((char *));
@@ -4024,7 +4114,7 @@ CVS server internal error: unhandled case in server_updated");
if (file != NULL)
{
- buf_output (protocol, file, file_used);
+ buf_output (protocol, (char *) file, file_used);
free (file);
file = NULL;
}
@@ -4321,9 +4411,9 @@ serve_ignore (arg)
}
static int
-expand_proc (pargc, argv, where, mwhere, mfile, shorten,
+expand_proc (argc, argv, where, mwhere, mfile, shorten,
local_specified, omodule, msg)
- int *pargc;
+ int argc;
char **argv;
char *where;
char *mwhere;
@@ -4362,7 +4452,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten,
{
/* We may not need to do this anymore -- check the definition
of aliases before removing */
- if (*pargc == 1)
+ if (argc == 1)
{
buf_output0 (buf_to_net, "Module-expansion ");
if (server_dir != NULL)
@@ -4375,7 +4465,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten,
}
else
{
- for (i = 1; i < *pargc; ++i)
+ for (i = 1; i < argc; ++i)
{
buf_output0 (buf_to_net, "Module-expansion ");
if (server_dir != NULL)
@@ -4467,24 +4557,27 @@ serve_checkin_prog (arg)
f = CVS_FOPEN (CVSADM_CIPROG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text,
"E cannot write to %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
}
@@ -4510,23 +4603,26 @@ E Flag -u in modules not allowed in readonly mode");
f = CVS_FOPEN (CVSADM_UPROG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot write to %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
}
@@ -4579,7 +4675,7 @@ struct request requests[] =
REQ_LINE("Case", serve_case, 0),
REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL),
REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL),
- REQ_LINE("Global_option", serve_global_option, 0),
+ REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS),
REQ_LINE("Gzip-stream", serve_gzip_stream, 0),
REQ_LINE("wrapper-sendme-rcsOptions",
serve_wrapper_sendme_rcs_options,
@@ -4623,7 +4719,8 @@ struct request requests[] =
REQ_LINE("editors", serve_editors, 0),
REQ_LINE("init", serve_init, RQ_ROOTLESS),
REQ_LINE("annotate", serve_annotate, 0),
- REQ_LINE("noop", serve_noop, 0),
+ REQ_LINE("noop", serve_noop, RQ_ROOTLESS),
+ REQ_LINE("version", serve_version, RQ_ROOTLESS),
REQ_LINE(NULL, NULL, 0)
#undef REQ_LINE
@@ -4847,16 +4944,10 @@ server (argc, argv)
for that case. */
if (!isabsolute (Tmpdir))
{
- pending_error_text = malloc (80 + strlen (Tmpdir));
- if (pending_error_text == NULL)
- {
- pending_error = ENOMEM;
- }
- else
- {
+ if (alloc_pending (80 + strlen (Tmpdir)))
sprintf (pending_error_text,
"E Value of %s for TMPDIR is not absolute", Tmpdir);
- }
+
/* FIXME: we would like this error to be persistent, that
is, not cleared by print_pending_error. The current client
will exit as soon as it gets an error, but the protocol spec
@@ -4865,6 +4956,7 @@ server (argc, argv)
else
{
int status;
+ int i = 0;
server_temp_dir = malloc (strlen (Tmpdir) + 80);
if (server_temp_dir == NULL)
@@ -4911,12 +5003,21 @@ error ENOMEM Virtual memory exhausted.\n");
/* Create the temporary directory, and set the mode to
700, to discourage random people from tampering with
it. */
- status = mkdir_p (server_temp_dir);
- if (status != 0 && status != EEXIST)
+ while ((status = mkdir_p (server_temp_dir)) == EEXIST)
{
- if (alloc_pending (80))
- strcpy (pending_error_text,
- "E can't create temporary directory");
+ static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
+
+ if (i >= sizeof suffix - 1) break;
+ if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
+ p[0] = suffix[i++];
+ p[1] = '\0';
+ }
+ if (status != 0)
+ {
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+ "E can't create temporary directory %s",
+ server_temp_dir);
pending_error = status;
}
#ifndef CHMOD_BROKEN
@@ -4925,9 +5026,10 @@ error ENOMEM Virtual memory exhausted.\n");
if (chmod (server_temp_dir, S_IRWXU) < 0)
{
int save_errno = errno;
- if (alloc_pending (80))
- strcpy (pending_error_text, "\
-E cannot change permissions on temporary directory");
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+"E cannot change permissions on temporary directory %s",
+ server_temp_dir);
pending_error = save_errno;
}
}
@@ -4935,6 +5037,9 @@ E cannot change permissions on temporary directory");
}
}
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, server_cleanup);
+#endif
#ifdef SIGHUP
(void) SIG_register (SIGHUP, server_cleanup);
#endif
@@ -5114,7 +5219,7 @@ error 0 %s: no such user\n", username);
if (setgid (getegid ()) < 0)
{
/* See comments at setuid call below for more discussion. */
- printf ("error 0 setuid failed: %s\n", strerror (errno));
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
/* Don't worry about server_cleanup;
server_active isn't set yet. */
error_exit ();
@@ -5126,7 +5231,7 @@ error 0 %s: no such user\n", username);
if (setgid (pw->pw_gid) < 0)
{
/* See comments at setuid call below for more discussion. */
- printf ("error 0 setuid failed: %s\n", strerror (errno));
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
/* Don't worry about server_cleanup;
server_active isn't set yet. */
error_exit ();
@@ -5151,6 +5256,12 @@ error 0 %s: no such user\n", username);
the client. */
umask (0);
+#ifdef AUTH_SERVER_SUPPORT
+ /* Make sure our CVS_Username has been set. */
+ if (CVS_Username == NULL)
+ CVS_Username = xstrdup (username);
+#endif
+
#if HAVE_PUTENV
/* Set LOGNAME and USER in the environment, in case they are
already set to something else. */
@@ -5176,14 +5287,15 @@ extern char *crypt PROTO((const char *, const char *));
/*
* 0 means no entry found for this user.
- * 1 means entry found and password matches.
+ * 1 means entry found and password matches (or found password is empty)
* 2 means entry found, but password does not match.
*
- * If success, host_user_ptr will be set to point at the system
+ * If 1, host_user_ptr will be set to point at the system
* username (i.e., the "real" identity, which may or may not be the
* CVS username) of this user; caller may free this. Global
* CVS_Username will point at an allocated copy of cvs username (i.e.,
* the username argument below).
+ * kff todo: FIXME: last sentence is not true, it applies to caller.
*/
static int
check_repository_password (username, password, repository, host_user_ptr)
@@ -5236,21 +5348,72 @@ check_repository_password (username, password, repository, host_user_ptr)
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", filename);
- /* If found_it != 0, then linebuf contains the information we need. */
+ /* If found_it, then linebuf contains the information we need. */
if (found_it)
{
- char *found_password, *host_user_tmp = NULL;
- char *linebufp = linebuf;
+ char *found_password, *host_user_tmp;
+ char *non_cvsuser_portion;
+
+ /* We need to make sure lines such as
+ *
+ * "username::sysuser\n"
+ * "username:\n"
+ * "username: \n"
+ *
+ * all result in a found_password of NULL, but we also need to
+ * make sure that
+ *
+ * "username: :sysuser\n"
+ * "username: <whatever>:sysuser\n"
+ *
+ * continues to result in an impossible password. That way,
+ * an admin would be on safe ground by going in and tacking a
+ * space onto the front of a password to disable the account
+ * (a technique some people use to close accounts
+ * temporarily).
+ */
+
+ /* Make `non_cvsuser_portion' contain everything after the CVS
+ username, but null out any final newline. */
+ non_cvsuser_portion = linebuf + namelen;
+ strtok (non_cvsuser_portion, "\n");
+
+ /* If there's a colon now, we just want to inch past it. */
+ if (strchr (non_cvsuser_portion, ':') == non_cvsuser_portion)
+ non_cvsuser_portion++;
+
+ /* Okay, after this conditional chain, found_password and
+ host_user_tmp will have useful values: */
+
+ if ((non_cvsuser_portion == NULL)
+ || (strlen (non_cvsuser_portion) == 0)
+ || ((strspn (non_cvsuser_portion, " \t"))
+ == strlen (non_cvsuser_portion)))
+ {
+ found_password = NULL;
+ host_user_tmp = NULL;
+ }
+ else if (strncmp (non_cvsuser_portion, ":", 1) == 0)
+ {
+ found_password = NULL;
+ host_user_tmp = non_cvsuser_portion + 1;
+ if (strlen (host_user_tmp) == 0)
+ host_user_tmp = NULL;
+ }
+ else
+ {
+ found_password = strtok (non_cvsuser_portion, ":");
+ host_user_tmp = strtok (NULL, ":");
+ }
- strsep (&linebufp, ":");
- found_password = strsep (&linebufp, ": \n");
- if (found_password)
- host_user_tmp = strsep (&linebufp, ": \n");
+ /* Of course, maybe there was no system user portion... */
if (host_user_tmp == NULL)
host_user_tmp = username;
- if (found_password == NULL || *found_password == '\0' ||
- strcmp (found_password, crypt (password, found_password)) == 0)
+ /* Verify blank passwords directly, otherwise use crypt(). */
+ if ((found_password == NULL)
+ || ((strcmp (found_password, crypt (password, found_password))
+ == 0)))
{
/* Give host_user_ptr permanent storage. */
*host_user_ptr = xstrdup (host_user_tmp);
@@ -5262,7 +5425,7 @@ check_repository_password (username, password, repository, host_user_ptr)
retval = 2;
}
}
- else
+ else /* Didn't find this user, so deny access. */
{
*host_user_ptr = NULL;
retval = 0;
@@ -5348,14 +5511,14 @@ error 0 %s: no such user\n", username);
/* user exists and has a password */
host_user = ((! strcmp (found_passwd,
crypt (password, found_passwd)))
- ? username : NULL);
+ ? xstrdup (username) : NULL);
goto handle_return;
}
else if (password && *password)
{
/* user exists and has no system password, but we got
one as parameter */
- host_user = username;
+ host_user = xstrdup (username);
goto handle_return;
}
else
@@ -5485,7 +5648,7 @@ pserver_authenticate_connection ()
#endif
/* Make sure the protocol starts off on the right foot... */
- if (getline (&tmp, &tmp_allocated, stdin) < 0)
+ if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0)
/* FIXME: what? We could try writing error/eof, but chances
are the network connection is dead bidirectionally. log it
somewhere? */
@@ -5516,9 +5679,9 @@ pserver_authenticate_connection ()
/* Get the three important pieces of information in order. */
/* See above comment about error handling. */
- getline (&repository, &repository_allocated, stdin);
- getline (&username, &username_allocated, stdin);
- getline (&password, &password_allocated, stdin);
+ getline_safe (&repository, &repository_allocated, stdin, PATH_MAX);
+ getline_safe (&username, &username_allocated, stdin, PATH_MAX);
+ getline_safe (&password, &password_allocated, stdin, PATH_MAX);
/* Make them pure. */
strip_trailing_newlines (repository);
@@ -5527,7 +5690,7 @@ pserver_authenticate_connection ()
/* ... and make sure the protocol ends on the right foot. */
/* See above comment about error handling. */
- getline (&tmp, &tmp_allocated, stdin);
+ getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX);
if (strcmp (tmp,
verify_and_exit ?
"END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n")
@@ -5589,6 +5752,7 @@ pserver_authenticate_connection ()
/* Switch to run as this user. */
switch_to_user (host_user);
+ free (host_user);
free (tmp);
free (repository);
free (username);
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index 89e8323..bec2397 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -96,6 +96,7 @@ static char *tag_update_dir;
static char *join_rev1, *date_rev1;
static char *join_rev2, *date_rev2;
static int aflag = 0;
+static int toss_local_changes = 0;
static int force_tag_match = 1;
static int update_build_dirs = 0;
static int update_prune_dirs = 0;
@@ -112,6 +113,7 @@ static const char *const update_usage[] =
" [-I ign] [-W spec] [files...]\n",
"\t-A\tReset any sticky tags/date/kopts.\n",
"\t-P\tPrune empty directories.\n",
+ "\t-C\tOverwrite locally modified files with clean repository copies.\n",
"\t-d\tBuild directories, like checkout does.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, no recursion.\n",
@@ -147,13 +149,16 @@ update (argc, argv)
/* parse the args */
optind = 0;
- while ((c = getopt (argc, argv, "+ApPflRQqduk:r:D:j:I:W:")) != -1)
+ while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1)
{
switch (c)
{
case 'A':
aflag = 1;
break;
+ case 'C':
+ toss_local_changes = 1;
+ break;
case 'I':
ign_add (optarg, 0);
break;
@@ -254,6 +259,8 @@ update (argc, argv)
send_arg("-f");
if (aflag)
send_arg("-A");
+ if (toss_local_changes)
+ send_arg("-C");
if (update_prune_dirs)
send_arg("-P");
client_prune_dirs = update_prune_dirs;
@@ -268,28 +275,35 @@ update (argc, argv)
option_with_arg ("-j", join_rev2);
wrap_send ();
- /* If the server supports the command "update-patches", that means
- that it knows how to handle the -u argument to update, which
- means to send patches instead of complete files.
-
- We don't send -u if failed_patches != NULL, so that the
- server doesn't try to send patches which will just fail
- again. At least currently, the client also clobbers the
- file and tells the server it is lost, which also will get
- a full file instead of a patch, but it seems clean to omit
- -u. */
- if (failed_patches == NULL)
+ if (failed_patches_count == 0)
{
+ unsigned int flags = 0;
+
+ /* If the server supports the command "update-patches", that
+ means that it knows how to handle the -u argument to update,
+ which means to send patches instead of complete files.
+
+ We don't send -u if failed_patches != NULL, so that the
+ server doesn't try to send patches which will just fail
+ again. At least currently, the client also clobbers the
+ file and tells the server it is lost, which also will get
+ a full file instead of a patch, but it seems clean to omit
+ -u. */
if (supported_request ("update-patches"))
send_arg ("-u");
- }
- if (failed_patches == NULL)
- {
+ if (update_build_dirs)
+ flags |= SEND_BUILD_DIRS;
+
+ if (toss_local_changes) {
+ flags |= SEND_NO_CONTENTS;
+ flags |= BACKUP_MODIFIED_FILES;
+ }
+
/* If noexec, probably could be setting SEND_NO_CONTENTS.
Same caveats as for "cvs status" apply. */
- send_files (argc, argv, local, aflag,
- update_build_dirs ? SEND_BUILD_DIRS : 0);
+
+ send_files (argc, argv, local, aflag, flags);
send_file_names (argc, argv, SEND_EXPAND_WILD);
}
else
@@ -313,11 +327,9 @@ update (argc, argv)
send_files (failed_patches_count, failed_patches, local,
aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
send_file_names (failed_patches_count, failed_patches, 0);
+ free_names (&failed_patches_count, failed_patches);
}
- failed_patches = NULL;
- failed_patches_count = 0;
-
send_to_server ("update\012", 0);
status = get_responses_and_close ();
@@ -336,13 +348,15 @@ update (argc, argv)
conflict-and-patch-failed case. */
if (status != 0
- && (failed_patches == NULL || pass > 1))
+ && (failed_patches_count == 0 || pass > 1))
{
+ if (failed_patches_count > 0)
+ free_names (&failed_patches_count, failed_patches);
return status;
}
++pass;
- } while (failed_patches != NULL);
+ } while (failed_patches_count > 0);
return 0;
}
@@ -368,15 +382,20 @@ update (argc, argv)
error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
#ifdef SERVER_SUPPORT
if (server_active)
- server_clear_entstat (".", Name_Repository (NULL, NULL));
+ {
+ char *repos = Name_Repository (NULL, NULL);
+ server_clear_entstat (".", repos);
+ free (repos);
+ }
#endif
}
/* keep the CVS/Tag file current with the specified arguments */
if (aflag || tag || date)
{
- WriteTag ((char *) NULL, tag, date, 0,
- ".", Name_Repository (NULL, NULL));
+ char *repos = Name_Repository (NULL, NULL);
+ WriteTag ((char *) NULL, tag, date, 0, ".", repos);
+ free (repos);
rewrite_tag = 1;
nonbranch = 0;
}
@@ -486,17 +505,11 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
argc, argv, local, which, aflag, 1,
preload_update_dir, 1);
- /* see if we need to sleep before returning */
+ /* see if we need to sleep before returning to avoid time-stamp races */
if (last_register_time)
{
- time_t now;
-
- for (;;)
- {
- (void) time (&now);
- if (now != last_register_time) break;
- sleep (1); /* to avoid time-stamp races */
- }
+ while (time ((time_t *) NULL) == last_register_time)
+ sleep (1);
}
return (err);
@@ -643,54 +656,82 @@ update_fileproc (callerdat, finfo)
break;
case T_MODIFIED: /* locally modified */
retval = 0;
- if (vers->ts_conflict)
- {
- char *filestamp;
- int retcode;
+ if (toss_local_changes)
+ {
+ char *bakname;
+ bakname = backup_file (finfo->file, vers->vn_user);
+ /* This behavior is sufficiently unexpected to
+ justify overinformativeness, I think. */
+#ifdef SERVER_SUPPORT
+ if ((! really_quiet) && (! server_active))
+#else /* ! SERVER_SUPPORT */
+ if (! really_quiet)
+#endif /* SERVER_SUPPORT */
+ (void) printf ("(Locally modified %s moved to %s)\n",
+ finfo->file, bakname);
+ free (bakname);
+
+ /* The locally modified file is still present, but
+ it will be overwritten by the repository copy
+ after this. */
+ status = T_CHECKOUT;
+ retval = checkout_file (finfo, vers, 0, 0, 1);
+ }
+ else
+ {
+ if (vers->ts_conflict)
+ {
+ char *filestamp;
+ int retcode;
+
+ /*
+ * If the timestamp has changed and no
+ * conflict indicators are found, it isn't a
+ * 'C' any more.
+ */
- /*
- * If the timestamp has changed and no conflict indicators
- * are found, it isn't a 'C' any more.
- */
#ifdef SERVER_SUPPORT
- if (server_active)
- retcode = vers->ts_conflict[0] != '=';
- else {
- filestamp = time_stamp (finfo->file);
- retcode = strcmp (vers->ts_conflict, filestamp);
- free (filestamp);
- }
+ if (server_active)
+ retcode = vers->ts_conflict[0] != '=';
+ else
+ {
+ filestamp = time_stamp (finfo->file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+ }
#else
- filestamp = time_stamp (finfo->file);
- retcode = strcmp (vers->ts_conflict, filestamp);
- free (filestamp);
+ filestamp = time_stamp (finfo->file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
#endif
- if (retcode)
- {
- /* The timestamps differ. But if there are conflict
- markers print 'C' anyway. */
- retcode = !file_has_markers (finfo);
- }
-
- if (!retcode)
- {
- write_letter (finfo, 'C');
- retval = 1;
- }
- else
- {
- /* Reregister to clear conflict flag. */
- Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs,
- vers->options, vers->tag,
- vers->date, (char *)0);
- }
- }
- if (!retval)
- {
- write_letter (finfo, 'M');
- retval = 0;
- }
+ if (retcode)
+ {
+ /* The timestamps differ. But if there
+ are conflict markers print 'C' anyway. */
+ retcode = !file_has_markers (finfo);
+ }
+
+ if (!retcode)
+ {
+ write_letter (finfo, 'C');
+ retval = 1;
+ }
+ else
+ {
+ /* Reregister to clear conflict flag. */
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs, vers->ts_rcs,
+ vers->options, vers->tag,
+ vers->date, (char *)0);
+ }
+ }
+ if (!retval)
+ {
+ write_letter (finfo, 'M');
+ retval = 0;
+ }
+ }
break;
#ifdef SERVER_SUPPORT
case T_PATCH: /* needs patch */
@@ -930,7 +971,8 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
/* This is a guess. We will rewrite it later
via WriteTag. */
0,
- 0);
+ 0,
+ 1);
rewrite_tag = 1;
nonbranch = 0;
Subdir_Register (entries, (char *) NULL, dir);
@@ -1016,6 +1058,10 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
{
FILE *fp;
+ /* Delete the ignore list if it hasn't already been done. */
+ if (ignlist)
+ dellist (&ignlist);
+
/* If we set the tag or date for a new subdirectory in
update_dirent_proc, and we're now done with that subdirectory,
undo the tag/date setting. Note that we know that the tag and
@@ -1061,6 +1107,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
cvs_output (": Executing '", 0);
run_print (stdout);
cvs_output ("'\n", 0);
+ cvs_flushout ();
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
else if (ferror (fp))
@@ -2051,7 +2098,7 @@ join_file (finfo, vers)
Vers_TS *vers;
{
char *backup;
- char *options;
+ char *t_options;
int status;
char *rev1;
@@ -2286,6 +2333,13 @@ join_file (finfo, vers)
xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
+ /* Reset any keyword expansion option. Otherwise, when a
+ command like `cvs update -kk -jT1 -jT2' creates a new file
+ (because a file had the T2 tag, but not T1), the subsequent
+ commit of that just-added file effectively would set the
+ admin `-kk' option for that file in the repository. */
+ options = NULL;
+
/* FIXME: If checkout_file fails, we should arrange to
return a non-zero exit status. */
status = checkout_file (finfo, xvers, 1, 0, 1);
@@ -2328,11 +2382,11 @@ join_file (finfo, vers)
if (jdate2 != NULL)
error (0, 0,
- "file %s is present in revision %s as of %s",
+ "file %s does not exist, but is present in revision %s as of %s",
finfo->fullname, jrev2, jdate2);
else
error (0, 0,
- "file %s is present in revision %s",
+ "file %s does not exist, but is present in revision %s",
finfo->fullname, jrev2);
/* FIXME: Should we arrange to return a non-zero exit status? */
@@ -2374,10 +2428,10 @@ join_file (finfo, vers)
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);
- options = vers->options;
+ t_options = vers->options;
#if 0
- if (*options == '\0')
- options = "-kk"; /* to ignore keyword expansions */
+ if (*t_options == '\0')
+ t_options = "-kk"; /* to ignore keyword expansions */
#endif
/* If the source of the merge is the same as the working file
@@ -2395,12 +2449,12 @@ join_file (finfo, vers)
/* This is because of the worry below about $Name. If that
isn't a problem, I suspect this code probably works for
text files too. */
- && (strcmp (options, "-kb") == 0
+ && (strcmp (t_options, "-kb") == 0
|| wrap_merge_is_copy (finfo->file)))
{
/* FIXME: what about nametag? What does RCS_merge do with
$Name? */
- if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
status = 2;
else
@@ -2424,7 +2478,7 @@ join_file (finfo, vers)
print. */
write_letter (finfo, 'U');
}
- else if (strcmp (options, "-kb") == 0
+ else if (strcmp (t_options, "-kb") == 0
|| wrap_merge_is_copy (finfo->file)
|| special_file_mismatch (finfo, rev1, rev2))
{
@@ -2434,7 +2488,7 @@ join_file (finfo, vers)
the two files, and let them resolve it. It is possible
that we should require a "touch foo" or similar step before
we allow a checkin. */
- if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
status = 2;
else
@@ -2465,7 +2519,7 @@ join_file (finfo, vers)
}
else
status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
- options, rev1, rev2);
+ t_options, rev1, rev2);
if (status != 0 && status != 1)
{
@@ -2496,9 +2550,9 @@ join_file (finfo, vers)
(void) time (&last_register_time);
cp = time_stamp (finfo->file);
}
- Register (finfo->entries, finfo->file, vers->vn_rcs,
- "Result of merge", vers->options, vers->tag,
- vers->date, cp);
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge",
+ vers->options, vers->tag, vers->date, cp);
if (cp)
free(cp);
}
@@ -2546,8 +2600,8 @@ special_file_mismatch (finfo, rev1, rev2)
dev_t rev1_dev, rev2_dev;
char *rev1_symlink = NULL;
char *rev2_symlink = NULL;
- List *rev1_hardlinks;
- List *rev2_hardlinks;
+ List *rev1_hardlinks = NULL;
+ List *rev2_hardlinks = NULL;
int check_uids, check_gids, check_modes;
int result;
@@ -2576,6 +2630,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_symlink = xreadlink (finfo->file);
else
{
+#ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2584,6 +2639,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_mode = sb.st_mode;
if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
rev1_dev = sb.st_rdev;
+#else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+#endif
}
rev1_hardlinks = list_linked_files_on_disk (finfo->file);
}
@@ -2649,6 +2708,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_symlink = xreadlink (finfo->file);
else
{
+#ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2657,6 +2717,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_mode = sb.st_mode;
if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
rev2_dev = sb.st_rdev;
+#else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+#endif
}
rev2_hardlinks = list_linked_files_on_disk (finfo->file);
}
OpenPOWER on IntegriCloud