summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2004-04-15 01:17:28 +0000
committerpeter <peter@FreeBSD.org>2004-04-15 01:17:28 +0000
commit39ae581ddb391e383fd37d518ec522be89358f41 (patch)
treeb312c05df2e7727eeb7186945c2c2e65f812ac05 /contrib
parent3aa249bff61808355fd6b864b94fd531fd00b3b7 (diff)
downloadFreeBSD-src-39ae581ddb391e383fd37d518ec522be89358f41.zip
FreeBSD-src-39ae581ddb391e383fd37d518ec522be89358f41.tar.gz
Initial merge of cvs-1.11.5 -> 1.11.15 changes onto mainline
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/cvs/contrib/sccs2rcs.in51
-rw-r--r--contrib/cvs/diff/diff3.c1
-rw-r--r--contrib/cvs/man/cvs.128
-rw-r--r--contrib/cvs/src/buffer.c114
-rw-r--r--contrib/cvs/src/checkout.c176
-rw-r--r--contrib/cvs/src/client.c1324
-rw-r--r--contrib/cvs/src/commit.c709
-rw-r--r--contrib/cvs/src/cvs.h227
-rw-r--r--contrib/cvs/src/diff.c436
-rw-r--r--contrib/cvs/src/entries.c53
-rw-r--r--contrib/cvs/src/filesubr.c212
-rw-r--r--contrib/cvs/src/import.c70
-rw-r--r--contrib/cvs/src/lock.c170
-rw-r--r--contrib/cvs/src/login.c43
-rw-r--r--contrib/cvs/src/logmsg.c76
-rw-r--r--contrib/cvs/src/main.c61
-rw-r--r--contrib/cvs/src/mkmodules.c20
-rw-r--r--contrib/cvs/src/parseinfo.c60
-rw-r--r--contrib/cvs/src/rcs.c573
-rw-r--r--contrib/cvs/src/rcs.h47
-rw-r--r--contrib/cvs/src/rcscmds.c139
-rw-r--r--contrib/cvs/src/recurse.c102
-rw-r--r--contrib/cvs/src/server.c1105
-rw-r--r--contrib/cvs/src/update.c370
-rw-r--r--contrib/cvs/src/update.h4
25 files changed, 3248 insertions, 2923 deletions
diff --git a/contrib/cvs/contrib/sccs2rcs.in b/contrib/cvs/contrib/sccs2rcs.in
index 2cd4813..b00ca88 100755
--- a/contrib/cvs/contrib/sccs2rcs.in
+++ b/contrib/cvs/contrib/sccs2rcs.in
@@ -42,6 +42,12 @@
# ...!harvard!cg-atla!viewlog!kenstir
#
# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
+#
+# Modified to detect SCCS binary files. If binary, skip the keyword
+# substitution and flag the RCS file as binary (using rcs -i -kb).
+# -Allan G. Schrum schrum@ofsoptics.com agschrum@mindspring.com
+# Fri Sep 26 10:40:40 EDT 2003
+#
# $FreeBSD$
@@ -164,6 +170,13 @@ end
onintr ERROR
+sort -k 1,1 /dev/null >& /dev/null
+if ($status == 0) then
+ set sort_each_field = '-k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9'
+else
+ set sort_each_field = '+0 +1 +2 +3 +4 +5 +6 +7 +8'
+endif
+
############################################################
# Loop over every s-file in SCCS dir
#
@@ -173,7 +186,18 @@ foreach sfile (SCCS/s.*)
# work on each rev of that file in ascending order
set firsttime = 1
- sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+
+ # Only scan the file up to the "I" keyword, then see if
+ # the "f" keyword is set to binary. The SCCS file has
+ # <ctrl>-aI denoting the start of the file (or end of header).
+ set binary = (`sed -e '/^.I/,$d' < $sfile | grep '^.f e 1$'`)
+ #if ($#binary) then
+ # echo This is a binary file
+ #else
+ # echo This is not a binary file
+ #endif
+
+ sccs prs $file | grep "^D " | @AWK@ '{print $2}' | sed -e 's/\./ /g' | sort -n -u $sort_each_field | sed -e 's/ /./g' > $revfile
foreach rev (`cat $revfile`)
if ($status != 0) goto ERROR
@@ -182,23 +206,34 @@ foreach sfile (SCCS/s.*)
# Is the substr stuff and the +0 in the following awk script really
# necessary? It seems to me that if we didn't find the date format
# we expected in the output we have other problems.
- set date = `sccs prs -r$rev $file | awk '/^D / {print (substr($3,0,2)+0<70?20:19) $3, $4; exit}'`
- set author = `sccs prs -r$rev $file | awk '/^D / {print $5; exit}'`
+ # Note: Solaris awk does not like the following line. Use gawk
+ # mawk, or nawk instead.
+ set date = `sccs prs -r$rev $file | @AWK@ '/^D / {print (substr($3,0,2)+0<70?20:19) $3, $4; exit}'`
+ set author = `sccs prs -r$rev $file | @AWK@ '/^D / {print $5; exit}'`
echo ""
echo "==> file $file, rev=$rev, date=$date, author=$author"
sccs edit -r$rev $file >>& $logfile
if ($status != 0) goto ERROR
echo checked out of SCCS
- # add RCS keywords in place of SCCS keywords
- sed -f $sedfile $file > $tmpfile
- if ($status != 0) goto ERROR
- echo performed keyword substitutions
- cp $tmpfile $file
+ # add RCS keywords in place of SCCS keywords (only if not binary)
+ if ($#binary == 0) then
+ sed -f $sedfile $file > $tmpfile
+ if ($status != 0) goto ERROR
+ echo performed keyword substitutions
+ cp $tmpfile $file
+ endif
# check file into RCS
if ($firsttime) then
set firsttime = 0
+
+ if ($#binary) then
+ echo this is a binary file
+ # Mark initial, empty file as binary
+ rcs -i -kb -t$emptyfile $file
+ endif
+
if ($nodesc) then
echo about to do ci
echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
diff --git a/contrib/cvs/diff/diff3.c b/contrib/cvs/diff/diff3.c
index fc32abd..109e66e 100644
--- a/contrib/cvs/diff/diff3.c
+++ b/contrib/cvs/diff/diff3.c
@@ -1363,6 +1363,7 @@ read_diff (filea, fileb, output_placement)
if (close (fd) != 0)
diff3_perror_with_exit ("pipe close");
unlink (diffout);
+ free( diffout );
return diff_result + total;
}
diff --git a/contrib/cvs/man/cvs.1 b/contrib/cvs/man/cvs.1
index 968227f..c11c6fd 100644
--- a/contrib/cvs/man/cvs.1
+++ b/contrib/cvs/man/cvs.1
@@ -209,14 +209,6 @@ Do not read the
.B cvs
startup file (\fI~/.cvsrc\fP).
.TP
-.B \-l
-Do not log the
-.I cvs_command
-in the command history (but execute it anyway). See the description
-of the
-.B history
-command for information on command history.
-.TP
.B \-n
Do not change any files. Attempt to execute the
.IR cvs_command ,
@@ -549,15 +541,6 @@ subdirectories. Available with the following commands:
.BR checkout ", " commit ", " diff ", "
.BR export ", " remove ", " rdiff ", " rtag ", "
.BR status ", " tag ", and " update .
-.I Warning:
-this is not the same
-as the overall
-.` "cvs \-l"
-option, which you can specify to the
-.I left
-of a
-.B cvs
-command!
.TP
.B \-n
Do
@@ -1095,7 +1078,7 @@ Others would simply do
.` "cvs checkout -rEXPR1 whatever_module"
to work with you on the experimental change.
.TP
-\fBdiff\fP [\fB\-kl\fP] [\fIrcsdiff_options\fP] [[\fB\-r\fP \fIrev1\fP | \fB\-D\fP \fIdate1\fP | \fB\-j\fP \fIrev1:date1\fP] [\fB\-r\fP \fIrev2\fP | \fB\-D\fP \fIdate2\fP | \fB\-j\fP \fIrev2:date2\fP]] [\fIfiles.\|.\|.\fP]
+\fBdiff\fP [\fB\-kl\fP] [\fIformat_options\fP] [[\fB\-r\fP \fIrev1\fP | \fB\-D\fP \fIdate1\fP | \fB\-j\fP \fIrev1:date1\fP] [\fB\-r\fP \fIrev2\fP | \fB\-D\fP \fIdate2\fP | \fB\-j\fP \fIrev2:date2\fP]] [\fIfiles.\|.\|.\fP]
.I Requires:
working directory, repository.
.br
@@ -1131,8 +1114,9 @@ and
options can be mixed together with at most two options ever specified.
.SP
See
-.BR rcsdiff ( 1 )
-for a list of other accepted options.
+.` "cvs --help diff"
+for a list of supported
+.IR format_options .
.SP
If you don't specify any files,
.B diff
@@ -1463,7 +1447,7 @@ is able to find the files that are located in other directories.
.SP
The standard option \fIflags\fP \fB\-f\fP, and \fB\-l\fP
are available with this command. There are also several
-special options flags:
+special option flags:
.SP
If you use the
.B \-s
@@ -1932,7 +1916,7 @@ Files in home directories:
\&.cvsrc
The
.B cvs
-initialisation file. Lines in this file can be used to specify default
+initialization file. Lines in this file can be used to specify default
options for each
.B cvs
command. For example the line
diff --git a/contrib/cvs/src/buffer.c b/contrib/cvs/src/buffer.c
index f190be2..d53a5c6 100644
--- a/contrib/cvs/src/buffer.c
+++ b/contrib/cvs/src/buffer.c
@@ -62,6 +62,11 @@ void
buf_free (buf)
struct buffer *buf;
{
+ if (buf->closure != NULL)
+ {
+ free (buf->closure);
+ buf->closure = NULL;
+ }
if (buf->data != NULL)
{
buf->last->next = free_buffer_data;
@@ -139,8 +144,23 @@ get_buffer_data ()
return ret;
}
-/* See whether a buffer is empty. */
+
+/* See whether a buffer and its file descriptor is empty. */
+int
+buf_empty (buf)
+ struct buffer *buf;
+{
+ /* Try and read any data on the file descriptor first.
+ * We already know the descriptor is non-blocking.
+ */
+ buf_input_data (buf, NULL);
+ return buf_empty_p (buf);
+}
+
+
+
+/* See whether a buffer is empty. */
int
buf_empty_p (buf)
struct buffer *buf;
@@ -153,6 +173,8 @@ buf_empty_p (buf)
return 1;
}
+
+
#ifdef SERVER_FLOWCONTROL
/*
* Count how much data is stored in the buffer..
@@ -1210,6 +1232,8 @@ buf_shutdown (buf)
return 0;
}
+
+
/* The simplest type of buffer is one built on top of a stdio FILE.
For simplicity, and because it is all that is required, we do not
implement setting this type of buffer into nonblocking mode. The
@@ -1220,14 +1244,17 @@ static int stdio_buffer_output PROTO((void *, const char *, int, int *));
static int stdio_buffer_flush PROTO((void *));
static int stdio_buffer_shutdown PROTO((struct buffer *buf));
-/* Initialize a buffer built on a stdio FILE. */
+
+/* Initialize a buffer built on a stdio FILE. */
struct stdio_buffer_closure
{
FILE *fp;
int child_pid;
};
+
+
struct buffer *
stdio_buffer_initialize (fp, child_pid, input, memory)
FILE *fp;
@@ -1353,8 +1380,9 @@ stdio_buffer_output (closure, data, have, wrote)
return 0;
}
-/* The buffer flush function for a buffer built on a stdio FILE. */
+
+/* The buffer flush function for a buffer built on a stdio FILE. */
static int
stdio_buffer_flush (closure)
void *closure;
@@ -1378,12 +1406,12 @@ static int
stdio_buffer_shutdown (buf)
struct buffer *buf;
{
- struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) buf->closure;
+ struct stdio_buffer_closure *bc = buf->closure;
struct stat s;
int closefp = 1;
/* Must be a pipe or a socket. What could go wrong? */
- assert (fstat ( fileno (bc->fp), &s ) != -1);
+ assert (fstat (fileno (bc->fp), &s) != -1);
/* Flush the buffer if we can */
if (buf->flush)
@@ -1394,30 +1422,11 @@ stdio_buffer_shutdown (buf)
if (buf->input)
{
- if ( !buf_empty_p (buf) )
- {
-# ifdef SERVER_SUPPORT
- if (server_active)
- /* FIXME: This should probably be sysloged since it doesn't
- * have anywhere else to go at this point.
- */
- error (0, 0, "dying gasps from client unexpected");
- else
-#endif
- error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
- }
- else if (ferror (bc->fp))
- {
-# ifdef SERVER_SUPPORT
- if (server_active)
- /* FIXME: This should probably be sysloged since it doesn't
- * have anywhere else to go at this point.
- */
- error (0, errno, "reading from client");
- else
-#endif
- error (0, errno, "reading from %s", current_parsed_root->hostname);
- }
+ /* There used to be a check here for unread data in the buffer of on
+ * the pipe, but it was deemed unnecessary and possibly dangerous. In
+ * some sense it could be second-guessing the caller who requested it
+ * closed, as well.
+ */
# ifdef SHUTDOWN_SERVER
if (current_parsed_root->method != server_method)
@@ -1425,8 +1434,8 @@ stdio_buffer_shutdown (buf)
# ifndef NO_SOCKET_TO_FD
{
/* shutdown() sockets */
- if (S_ISSOCK(s.st_mode))
- shutdown ( fileno (bc->fp), 0);
+ if (S_ISSOCK (s.st_mode))
+ shutdown (fileno (bc->fp), 0);
}
# endif /* NO_SOCKET_TO_FD */
# ifdef START_RSH_WITH_POPEN_RW
@@ -1448,13 +1457,13 @@ stdio_buffer_shutdown (buf)
* SHUTDOWN_SERVER_OUTPUT
*/
if (current_parsed_root->method == server_method)
- SHUTDOWN_SERVER ( fileno (bc->fp) );
+ SHUTDOWN_SERVER (fileno (bc->fp));
else
# endif
# ifndef NO_SOCKET_TO_FD
/* shutdown() sockets */
- if (S_ISSOCK(s.st_mode))
- shutdown ( fileno (bc->fp), 1);
+ if (S_ISSOCK (s.st_mode))
+ shutdown (fileno (bc->fp), 1);
# else
{
/* I'm not sure I like this empty block, but the alternative
@@ -1467,15 +1476,34 @@ stdio_buffer_shutdown (buf)
}
if (closefp && fclose (bc->fp) == EOF)
- error (1, errno,
- "closing down connection to %s",
- current_parsed_root->hostname);
+ {
+ if (0
+# ifdef SERVER_SUPPORT
+ || server_active
+# endif /* SERVER_SUPPORT */
+ )
+ {
+ /* Syslog this? */
+ }
+# ifdef CLIENT_SUPPORT
+ else
+ error (1, errno,
+ "closing down connection to %s",
+ current_parsed_root->hostname);
+# endif /* CLIENT_SUPPORT */
+ }
/* If we were talking to a process, make sure it exited */
- if (bc->child_pid
- && waitpid (bc->child_pid, (int *) 0, 0) == -1)
- error (1, errno, "waiting for process %d", bc->child_pid);
+ if (bc->child_pid)
+ {
+ int w;
+ do
+ w = waitpid (bc->child_pid, (int *) 0, 0);
+ while (w == -1 && errno == EINTR);
+ if (w == -1)
+ error (1, errno, "waiting for process %d", bc->child_pid);
+ }
return 0;
}
@@ -1874,8 +1902,9 @@ packetizing_buffer_output (closure, data, have, wrote)
return buf_send_output (pb->buf);
}
-/* Flush data to a packetizing buffer. */
+
+/* Flush data to a packetizing buffer. */
static int
packetizing_buffer_flush (closure)
void *closure;
@@ -1889,8 +1918,9 @@ packetizing_buffer_flush (closure)
return buf_flush (pb->buf, 0);
}
-/* The block routine for a packetizing buffer. */
+
+/* The block routine for a packetizing buffer. */
static int
packetizing_buffer_block (closure, block)
void *closure;
diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c
index 6c0bba8..57933ee 100644
--- a/contrib/cvs/src/checkout.c
+++ b/contrib/cvs/src/checkout.c
@@ -136,7 +136,7 @@ checkout (argc, argv)
* options to be default (like -kv) and takes care to remove the CVS
* directory when it has done its duty
*/
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
m_type = EXPORT;
valid_options = "+Nnk:d:flRQqr:D:";
@@ -186,7 +186,7 @@ checkout (argc, argv)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
- command_name);
+ cvs_cmd_name);
break;
case 'l':
local = 1;
@@ -282,14 +282,6 @@ checkout (argc, argv)
ign_setup ();
- /* We have to expand names here because the "expand-modules"
- directive to the server has the side-effect of having the
- server send the check-in and update programs for the
- various modules/dirs requested. If we turn this off and
- simply request the names of the modules and directories (as
- below in !expand_modules), those files (CVS/Checkin.prog
- or CVS/Update.prog) don't get created. Grrr. */
-
expand_modules = (!cat && !pipeout
&& supported_request ("expand-modules"));
@@ -332,6 +324,7 @@ checkout (argc, argv)
option_with_arg ("-j", join_rev1);
if (join_rev2 != NULL)
option_with_arg ("-j", join_rev2);
+ send_arg ("--");
if (expand_modules)
{
@@ -407,39 +400,55 @@ checkout (argc, argv)
/* FIXME: This is and emptydir_name are in checkout.c for historical
reasons, probably want to move them. */
+/* int
+ * safe_location ( char *where )
+ *
+ * Return true if where is a safe destination for a checkout.
+ *
+ * INPUTS
+ * where The requested destination directory.
+ *
+ * GLOBALS
+ * current_parsed_root->directory
+ * current_parsed_root->isremote
+ * Used to locate our CVSROOT.
+ *
+ * RETURNS
+ * true If we are running in client mode or if where is not located
+ * within the CVSROOT.
+ * false Otherwise.
+ *
+ * ERRORS
+ * Exits with a fatal error message when various events occur, such as not
+ * being able to resolve a path or failing ot chdir to a path.
+ */
int
safe_location (where)
char *where;
{
char *current;
char *where_location;
- char hardpath[PATH_MAX+5];
+ char *hardpath;
size_t hardpath_len;
- int x;
int retval;
-#ifdef HAVE_READLINK
- /* FIXME-arbitrary limit: should be retrying this like xgetwd.
- But how does readlink let us know that the buffer was too small?
- (by returning sizeof hardpath - 1?). */
- x = readlink(current_parsed_root->directory, hardpath, sizeof hardpath - 1);
-#else
- x = -1;
-#endif
- if (x == -1)
- {
- strcpy(hardpath, current_parsed_root->directory);
- }
- else
- {
- hardpath[x] = '\0';
- }
+ if (trace)
+ (void) fprintf (stderr, "%s-> safe_location( where=%s )\n",
+ CLIENT_SERVER_STR,
+ where ? where : "(null)");
+
+#ifdef CLIENT_SUPPORT
+ /* Don't compare remote CVSROOTs to our destination directory. */
+ if ( current_parsed_root->isremote ) return 1;
+#endif /* CLIENT_SUPPORT */
/* set current - even if where is set we'll need to cd back... */
current = xgetwd ();
if (current == NULL)
error (1, errno, "could not get working directory");
+ hardpath = xresolvepath ( current_parsed_root->directory );
+
/* if where is set, set current to where, where - last_component( where ),
* or fail, depending on whether the directories exist or not.
*/
@@ -466,12 +475,16 @@ safe_location (where)
char *parent;
/* strip the last_component */
- where_location = xstrdup( where );
- parent = last_component( where_location );
+ where_location = xstrdup (where);
+ /* It's okay to cast out the const below since we know we just
+ * allocated where_location and can do what we like with it.
+ */
+ parent = (char *)last_component (where_location);
parent[-1] = '\0';
if( chdir( where_location ) != -1 )
{
+ free( where_location );
where_location = xgetwd();
if( where_location == NULL )
error( 1, errno, "could not get working directory (nominally `%s')", where_location );
@@ -514,6 +527,7 @@ safe_location (where)
else
retval = 1;
free (current);
+ free (hardpath);
return retval;
}
@@ -927,52 +941,48 @@ internal error: %s doesn't start with %s in checkout_proc",
/* clean up */
free (reposcopy);
+ /* The top-level CVSADM directory should always be
+ current_parsed_root->directory. Create it, but only if WHERE is
+ relative. If WHERE is absolute, our current directory
+ may not have a thing to do with where the sources are
+ being checked out. If it does, build_dirs_and_chdir
+ will take care of creating adm files here. */
+ /* FIXME: checking is_absolute (where) is a horrid kludge;
+ I suspect we probably can just skip the call to
+ build_one_dir whenever the -d command option was specified
+ to checkout. */
+
+ if (!isabsolute (where) && top_level_admin && m_type == CHECKOUT)
{
- int where_is_absolute = isabsolute (where);
-
- /* The top-level CVSADM directory should always be
- current_parsed_root->directory. Create it, but only if WHERE is
- relative. If WHERE is absolute, our current directory
- may not have a thing to do with where the sources are
- being checked out. If it does, build_dirs_and_chdir
- will take care of creating adm files here. */
- /* FIXME: checking where_is_absolute is a horrid kludge;
- I suspect we probably can just skip the call to
- build_one_dir whenever the -d command option was specified
- to checkout. */
-
- if (! where_is_absolute && top_level_admin && m_type == CHECKOUT)
- {
- /* It may be argued that we shouldn't set any sticky
- bits for the top-level repository. FIXME? */
- build_one_dir (current_parsed_root->directory, ".", argc <= 1);
+ /* It may be argued that we shouldn't set any sticky
+ bits for the top-level repository. FIXME? */
+ build_one_dir (current_parsed_root->directory, ".", argc <= 1);
#ifdef SERVER_SUPPORT
- /* We _always_ want to have a top-level admin
- directory. If we're running in client/server mode,
- send a "Clear-static-directory" command to make
- sure it is created on the client side. (See 5.10
- in cvsclient.dvi to convince yourself that this is
- OK.) If this is a duplicate command being sent, it
- will be ignored on the client side. */
+ /* We _always_ want to have a top-level admin
+ directory. If we're running in client/server mode,
+ send a "Clear-static-directory" command to make
+ sure it is created on the client side. (See 5.10
+ in cvsclient.dvi to convince yourself that this is
+ OK.) If this is a duplicate command being sent, it
+ will be ignored on the client side. */
- if (server_active)
- server_clear_entstat (".", current_parsed_root->directory);
+ if (server_active)
+ server_clear_entstat (".", current_parsed_root->directory);
#endif
- }
+ }
- /* Build dirs on the path if necessary and leave us in the
- bottom directory (where if where was specified) doesn't
- contain a CVS subdir yet, but all the others contain
- CVS and Entries.Static files */
+ /* Build dirs on the path if necessary and leave us in the
+ bottom directory (where if where was specified) doesn't
+ contain a CVS subdir yet, but all the others contain
+ CVS and Entries.Static files */
- if (build_dirs_and_chdir (head, argc <= 1) != 0)
- {
- error (0, 0, "ignoring module %s", omodule);
- err = 1;
- goto out;
- }
+ if (build_dirs_and_chdir (head, argc <= 1) != 0)
+ {
+ error (0, 0, "ignoring module %s", omodule);
+ err = 1;
+ goto out;
}
/* set up the repository (or make sure the old one matches) */
@@ -1095,7 +1105,7 @@ internal error: %s doesn't start with %s in checkout_proc",
force_tag_match, 0 /* !local */ ,
1 /* update -d */ , aflag, checkout_prune_dirs,
pipeout, which, join_rev1, join_rev2,
- preload_update_dir, pull_template);
+ preload_update_dir, pull_template, repository);
goto out;
}
@@ -1151,7 +1161,7 @@ internal error: %s doesn't start with %s in checkout_proc",
err += do_update (argc - 1, argv + 1, options, tag, date,
force_tag_match, local_specified, 1 /* update -d */,
aflag, checkout_prune_dirs, pipeout, which, join_rev1,
- join_rev2, preload_update_dir, pull_template);
+ join_rev2, preload_update_dir, pull_template, repository);
out:
free (preload_update_dir);
preload_update_dir = oldupdate;
@@ -1201,8 +1211,28 @@ emptydir_name ()
}
/* Build all the dirs along the path to DIRS with CVS subdirs with appropriate
- repositories. If ->repository is NULL, do not create a CVSADM directory
- for that subdirectory; just CVS_CHDIR into it. */
+ * repositories. If DIRS->repository is NULL or the directory already exists,
+ * do not create a CVSADM directory for that subdirectory; just CVS_CHDIR into
+ * it. Frees all storage used by DIRS.
+ *
+ * ASSUMPTIONS
+ * 1. Parent directories will be listed in DIRS before their children.
+ * 2. At most a single directory will need to be changed at one time. In
+ * other words, if we are in /a/b/c, and our final destination is
+ * /a/b/c/d/e/f, then we will build d, then d/e, then d/e/f.
+ *
+ * INPUTS
+ * dirs Simple list composed of dir_to_build structures, listing
+ * information about directories to build.
+ * sticky Passed to build_one_dir to tell it whether there are any sticky
+ * tags or dates to be concerned with.
+ *
+ * RETURNS
+ * 1 on error, 0 otherwise.
+ *
+ * ERRORS
+ * The only nonfatal error this function may return is if the CHDIR fails.
+ */
static int
build_dirs_and_chdir (dirs, sticky)
struct dir_to_build *dirs;
@@ -1213,7 +1243,7 @@ build_dirs_and_chdir (dirs, sticky)
while (dirs != NULL)
{
- char *dir = last_component (dirs->dirpath);
+ const char *dir = last_component (dirs->dirpath);
if (!dirs->just_chdir)
{
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index 566eca3..ef2155f 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -1,5 +1,3 @@
-/* JT thinks BeOS is worth the trouble. */
-
/* CVS client-related stuff.
This program is free software; you can redistribute it and/or modify
@@ -25,12 +23,13 @@
#include "getline.h"
#include "edit.h"
#include "buffer.h"
+#include "savecwd.h"
#ifdef CLIENT_SUPPORT
# include "md5.h"
-# if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
+# if defined(AUTH_CLIENT_SUPPORT) || defined(HAVE_KERBEROS) || defined(HAVE_GSSAPI) || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
# ifdef HAVE_WINSOCK_H
# include <winsock.h>
# else /* No winsock.h */
@@ -90,7 +89,20 @@ static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *));
# endif /* HAVE_GSSAPI */
-static void add_prune_candidate PROTO((char *));
+
+
+/* Keep track of any paths we are sending for Max-dotdot so that we can verify
+ * that uplevel paths coming back form the server are valid.
+ *
+ * FIXME: The correct way to do this is probably provide some sort of virtual
+ * path map on the client side. This would be generic enough to be applied to
+ * absolute paths supplied by the user too.
+ */
+static List *uppaths = NULL;
+
+
+
+static void add_prune_candidate PROTO((const char *));
/* All the commands. */
int add PROTO((int argc, char **argv));
@@ -127,8 +139,6 @@ static void handle_set_static_directory PROTO((char *, int));
static void handle_clear_static_directory PROTO((char *, int));
static void handle_set_sticky PROTO((char *, int));
static void handle_clear_sticky PROTO((char *, int));
-static void handle_set_checkin_prog PROTO((char *, int));
-static void handle_set_update_prog PROTO((char *, int));
static void handle_module_expansion PROTO((char *, int));
static void handle_wrapper_rcs_option PROTO((char *, int));
static void handle_m PROTO((char *, int));
@@ -999,10 +1009,62 @@ handle_valid_requests (args, len)
}
}
-/* This variable holds the result of Entries_Open, so that we can
- close Entries_Close on it when we move on to a new directory, or
- when we finish. */
-static List *last_entries;
+
+
+/*
+ * This is a proc for walklist(). It inverts the error return premise of
+ * walklist.
+ *
+ * RETURNS
+ * True If this path is prefixed by one of the paths in walklist and
+ * does not step above the prefix path.
+ * False Otherwise.
+ */
+static
+int path_list_prefixed (p, closure)
+ Node *p;
+ void *closure;
+{
+ const char *questionable = closure;
+ const char *prefix = p->key;
+ if (strncmp (prefix, questionable, strlen (prefix))) return 0;
+ questionable += strlen (prefix);
+ while (ISDIRSEP (*questionable)) questionable++;
+ if (*questionable == '\0') return 1;
+ return pathname_levels (questionable);
+}
+
+
+
+/*
+ * Need to validate the client pathname. Disallowed paths include:
+ *
+ * 1. Absolute paths.
+ * 2. Pathnames that do not reference a specifically requested update
+ * directory.
+ *
+ * In case 2, we actually only check that the directory is under the uppermost
+ * directories mentioned on the command line.
+ *
+ * RETURNS
+ * True If the path is valid.
+ * False Otherwise.
+ */
+static
+int is_valid_client_path (pathname)
+ const char *pathname;
+{
+ /* 1. Absolute paths. */
+ if (isabsolute (pathname)) return 0;
+ /* 2. No up-references in path. */
+ if (pathname_levels (pathname) == 0) return 1;
+ /* 2. No Max-dotdot paths registered. */
+ if (uppaths == NULL) return 0;
+
+ return walklist (uppaths, path_list_prefixed, (void *)pathname);
+}
+
+
/*
* Do all the processing for PATHNAME, where pathname consists of the
@@ -1015,8 +1077,6 @@ static List *last_entries;
* SHORT_PATHNAME. When we call FUNC, the curent directory points to
* the directory portion of SHORT_PATHNAME. */
-static char *last_dir_name;
-
static void
call_in_directory (pathname, func, data)
char *pathname;
@@ -1024,6 +1084,8 @@ call_in_directory (pathname, func, data)
char *filename));
char *data;
{
+ /* This variable holds the result of Entries_Open. */
+ List *last_entries = NULL;
char *dir_name;
char *filename;
/* This is what we get when we hook up the directory (working directory
@@ -1053,6 +1115,7 @@ call_in_directory (pathname, func, data)
char *reposdirname;
char *rdirp;
int reposdirname_absolute;
+ int newdir = 0;
reposname = NULL;
read_line (&reposname);
@@ -1073,6 +1136,36 @@ call_in_directory (pathname, func, data)
short_repos = reposname;
}
}
+
+ /* Now that we have SHORT_REPOS, we can calculate the path to the file we
+ * are being requested to operate on.
+ */
+ filename = strrchr (short_repos, '/');
+ if (filename == NULL)
+ filename = short_repos;
+ else
+ ++filename;
+
+ short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
+ strcpy (short_pathname, pathname);
+ strcat (short_pathname, filename);
+
+ /* Now that we know the path to the file we were requested to operate on,
+ * we can verify that it is valid.
+ *
+ * For security reasons, if SHORT_PATHNAME is absolute or attempts to
+ * ascend outside of the current sanbbox, we abort. The server should not
+ * send us anything but relative paths which remain inside the sandbox
+ * here. Anything less means a trojan CVS server could create and edit
+ * arbitrary files on the client.
+ */
+ if (!is_valid_client_path (short_pathname))
+ {
+ error (0, 0,
+ "Server attempted to update a file via an invalid pathname:");
+ error (1, 0, "`%s'.", short_pathname);
+ }
+
reposdirname = xstrdup (short_repos);
p = strrchr (reposdirname, '/');
if (p == NULL)
@@ -1095,296 +1188,272 @@ call_in_directory (pathname, func, data)
if (client_prune_dirs)
add_prune_candidate (dir_name);
- filename = strrchr (short_repos, '/');
- if (filename == NULL)
- filename = short_repos;
- else
- ++filename;
-
- short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
- strcpy (short_pathname, pathname);
- strcat (short_pathname, filename);
-
- if (last_dir_name == NULL
- || strcmp (last_dir_name, dir_name) != 0)
+ if (toplevel_wd == NULL)
{
- int newdir;
-
- if (strcmp (command_name, "export") != 0)
- if (last_entries)
- Entries_Close (last_entries);
-
- if (last_dir_name)
- free (last_dir_name);
- last_dir_name = dir_name;
-
+ toplevel_wd = xgetwd ();
if (toplevel_wd == NULL)
- {
- toplevel_wd = xgetwd ();
- if (toplevel_wd == NULL)
- error (1, errno, "could not get working directory");
- }
-
- if (CVS_CHDIR (toplevel_wd) < 0)
- error (1, errno, "could not chdir to %s", toplevel_wd);
- newdir = 0;
-
- /* Create the CVS directory at the top level if needed. The
- isdir seems like an unneeded system call, but it *does*
- need to be called both if the CVS_CHDIR below succeeds
- (e.g. "cvs co .") or if it fails (e.g. basicb-1a in
- testsuite). We only need to do this for the "." case,
- since the server takes care of forcing this directory to be
- created in all other cases. If we don't create CVSADM
- here, the call to Entries_Open below will fail. FIXME:
- perhaps this means that we should change our algorithm
- below that calls Create_Admin instead of having this code
- here? */
- if (/* I think the reposdirname_absolute case has to do with
- things like "cvs update /foo/bar". In any event, the
- code below which tries to put toplevel_repos into
- CVS/Repository is almost surely unsuited to
- the reposdirname_absolute case. */
- !reposdirname_absolute
- && (strcmp (dir_name, ".") == 0)
- && ! isdir (CVSADM))
- {
- char *repo;
- char *r;
-
- newdir = 1;
-
- repo = xmalloc (strlen (toplevel_repos)
- + 10);
- strcpy (repo, toplevel_repos);
- r = repo + strlen (repo);
- if (r[-1] != '.' || r[-2] != '/')
- strcpy (r, "/.");
-
- Create_Admin (".", ".", repo, (char *) NULL,
- (char *) NULL, 0, 1, 1);
+ error (1, errno, "could not get working directory");
+ }
- free (repo);
- }
+ if (CVS_CHDIR (toplevel_wd) < 0)
+ error (1, errno, "could not chdir to %s", toplevel_wd);
+
+ /* Create the CVS directory at the top level if needed. The
+ isdir seems like an unneeded system call, but it *does*
+ need to be called both if the CVS_CHDIR below succeeds
+ (e.g. "cvs co .") or if it fails (e.g. basicb-1a in
+ testsuite). We only need to do this for the "." case,
+ since the server takes care of forcing this directory to be
+ created in all other cases. If we don't create CVSADM
+ here, the call to Entries_Open below will fail. FIXME:
+ perhaps this means that we should change our algorithm
+ below that calls Create_Admin instead of having this code
+ here? */
+ if (/* I think the reposdirname_absolute case has to do with
+ things like "cvs update /foo/bar". In any event, the
+ code below which tries to put toplevel_repos into
+ CVS/Repository is almost surely unsuited to
+ the reposdirname_absolute case. */
+ !reposdirname_absolute
+ && (strcmp (dir_name, ".") == 0)
+ && ! isdir (CVSADM))
+ {
+ char *repo;
+ char *r;
+
+ newdir = 1;
+
+ repo = xmalloc (strlen (toplevel_repos)
+ + 10);
+ strcpy (repo, toplevel_repos);
+ r = repo + strlen (repo);
+ if (r[-1] != '.' || r[-2] != '/')
+ strcpy (r, "/.");
+
+ Create_Admin (".", ".", repo, (char *) NULL,
+ (char *) NULL, 0, 1, 1);
+
+ free (repo);
+ }
- if ( CVS_CHDIR (dir_name) < 0)
+ if (CVS_CHDIR (dir_name) < 0)
+ {
+ char *dir;
+ char *dirp;
+
+ if (! existence_error (errno))
+ error (1, errno, "could not chdir to %s", dir_name);
+
+ /* Directory does not exist, we need to create it. */
+ newdir = 1;
+
+ /* Provided we are willing to assume that directories get
+ created one at a time, we could simplify this a lot.
+ Do note that one aspect still would need to walk the
+ dir_name path: the checking for "fncmp (dir, CVSADM)". */
+
+ dir = xmalloc (strlen (dir_name) + 1);
+ dirp = dir_name;
+ rdirp = reposdirname;
+
+ /* This algorithm makes nested directories one at a time
+ and create CVS administration files in them. For
+ example, we're checking out foo/bar/baz from the
+ repository:
+
+ 1) create foo, point CVS/Repository to <root>/foo
+ 2) .. foo/bar .. <root>/foo/bar
+ 3) .. foo/bar/baz .. <root>/foo/bar/baz
+
+ As you can see, we're just stepping along DIR_NAME (with
+ DIRP) and REPOSDIRNAME (with RDIRP) respectively.
+
+ We need to be careful when we are checking out a
+ module, however, since DIR_NAME and REPOSDIRNAME are not
+ going to be the same. Since modules will not have any
+ slashes in their names, we should watch the output of
+ STRCHR to decide whether or not we should use STRCHR on
+ the RDIRP. That is, if we're down to a module name,
+ don't keep picking apart the repository directory name. */
+
+ do
{
- char *dir;
- char *dirp;
-
- if (! existence_error (errno))
- error (1, errno, "could not chdir to %s", dir_name);
-
- /* Directory does not exist, we need to create it. */
- newdir = 1;
-
- /* Provided we are willing to assume that directories get
- created one at a time, we could simplify this a lot.
- Do note that one aspect still would need to walk the
- dir_name path: the checking for "fncmp (dir, CVSADM)". */
-
- dir = xmalloc (strlen (dir_name) + 1);
- dirp = dir_name;
- rdirp = reposdirname;
-
- /* This algorithm makes nested directories one at a time
- and create CVS administration files in them. For
- example, we're checking out foo/bar/baz from the
- repository:
-
- 1) create foo, point CVS/Repository to <root>/foo
- 2) .. foo/bar .. <root>/foo/bar
- 3) .. foo/bar/baz .. <root>/foo/bar/baz
-
- As you can see, we're just stepping along DIR_NAME (with
- DIRP) and REPOSDIRNAME (with RDIRP) respectively.
-
- We need to be careful when we are checking out a
- module, however, since DIR_NAME and REPOSDIRNAME are not
- going to be the same. Since modules will not have any
- slashes in their names, we should watch the output of
- STRCHR to decide whether or not we should use STRCHR on
- the RDIRP. That is, if we're down to a module name,
- don't keep picking apart the repository directory name. */
-
- do
+ dirp = strchr (dirp, '/');
+ if (dirp)
{
- dirp = strchr (dirp, '/');
- if (dirp)
- {
- strncpy (dir, dir_name, dirp - dir_name);
- dir[dirp - dir_name] = '\0';
- /* Skip the slash. */
- ++dirp;
- if (rdirp == NULL)
- /* This just means that the repository string has
- fewer components than the dir_name string. But
- that is OK (e.g. see modules3-8 in testsuite). */
- ;
- else
- rdirp = strchr (rdirp, '/');
- }
+ strncpy (dir, dir_name, dirp - dir_name);
+ dir[dirp - dir_name] = '\0';
+ /* Skip the slash. */
+ ++dirp;
+ if (rdirp == NULL)
+ /* This just means that the repository string has
+ fewer components than the dir_name string. But
+ that is OK (e.g. see modules3-8 in testsuite). */
+ ;
else
- {
- /* If there are no more slashes in the dir name,
- we're down to the most nested directory -OR- to
- the name of a module. In the first case, we
- should be down to a DIRP that has no slashes,
- so it won't help/hurt to do another STRCHR call
- on DIRP. It will definitely hurt, however, if
- we're down to a module name, since a module
- name can point to a nested directory (that is,
- DIRP will still have slashes in it. Therefore,
- we should set it to NULL so the routine below
- copies the contents of REMOTEDIRNAME onto the
- root repository directory (does this if rdirp
- is set to NULL, because we used to do an extra
- STRCHR call here). */
-
- rdirp = NULL;
- strcpy (dir, dir_name);
- }
+ rdirp = strchr (rdirp, '/');
+ }
+ else
+ {
+ /* If there are no more slashes in the dir name,
+ we're down to the most nested directory -OR- to
+ the name of a module. In the first case, we
+ should be down to a DIRP that has no slashes,
+ so it won't help/hurt to do another STRCHR call
+ on DIRP. It will definitely hurt, however, if
+ we're down to a module name, since a module
+ name can point to a nested directory (that is,
+ DIRP will still have slashes in it. Therefore,
+ we should set it to NULL so the routine below
+ copies the contents of REMOTEDIRNAME onto the
+ root repository directory (does this if rdirp
+ is set to NULL, because we used to do an extra
+ STRCHR call here). */
+
+ rdirp = NULL;
+ strcpy (dir, dir_name);
+ }
+
+ if (fncmp (dir, CVSADM) == 0)
+ {
+ error (0, 0, "cannot create a directory named %s", dir);
+ error (0, 0, "because CVS uses \"%s\" for its own uses",
+ CVSADM);
+ error (1, 0, "rename the directory and try again");
+ }
+
+ if (mkdir_if_needed (dir))
+ {
+ /* It already existed, fine. Just keep going. */
+ }
+ else if (strcmp (cvs_cmd_name, "export") == 0)
+ /* Don't create CVSADM directories if this is export. */
+ ;
+ else
+ {
+ /*
+ * Put repository in CVS/Repository. For historical
+ * (pre-CVS/Root) reasons, this is an absolute pathname,
+ * but what really matters is the part of it which is
+ * relative to cvsroot.
+ */
+ char *repo;
+ char *r, *b;
- if (fncmp (dir, CVSADM) == 0)
+ repo = xmalloc (strlen (reposdirname)
+ + strlen (toplevel_repos)
+ + 80);
+ if (reposdirname_absolute)
+ r = repo;
+ else
{
- error (0, 0, "cannot create a directory named %s", dir);
- error (0, 0, "because CVS uses \"%s\" for its own uses",
- CVSADM);
- error (1, 0, "rename the directory and try again");
+ strcpy (repo, toplevel_repos);
+ strcat (repo, "/");
+ r = repo + strlen (repo);
}
- if (mkdir_if_needed (dir))
+ if (rdirp)
{
- /* It already existed, fine. Just keep going. */
+ /* See comment near start of function; the only
+ way that the server can put the right thing
+ in each CVS/Repository file is to create the
+ directories one at a time. I think that the
+ CVS server has been doing this all along. */
+ error (0, 0, "\
+warning: server is not creating directories one at a time");
+ strncpy (r, reposdirname, rdirp - reposdirname);
+ r[rdirp - reposdirname] = '\0';
}
- else if (strcmp (command_name, "export") == 0)
- /* Don't create CVSADM directories if this is export. */
- ;
else
- {
- /*
- * Put repository in CVS/Repository. For historical
- * (pre-CVS/Root) reasons, this is an absolute pathname,
- * but what really matters is the part of it which is
- * relative to cvsroot.
- */
- char *repo;
- char *r, *b;
-
- repo = xmalloc (strlen (reposdirname)
- + strlen (toplevel_repos)
- + 80);
- if (reposdirname_absolute)
- r = repo;
- else
- {
- strcpy (repo, toplevel_repos);
- strcat (repo, "/");
- r = repo + strlen (repo);
- }
+ strcpy (r, reposdirname);
- if (rdirp)
- {
- /* See comment near start of function; the only
- way that the server can put the right thing
- in each CVS/Repository file is to create the
- directories one at a time. I think that the
- CVS server has been doing this all along. */
- error (0, 0, "\
-warning: server is not creating directories one at a time");
- strncpy (r, reposdirname, rdirp - reposdirname);
- r[rdirp - reposdirname] = '\0';
- }
- else
- strcpy (r, reposdirname);
-
- Create_Admin (dir, dir, repo,
- (char *)NULL, (char *)NULL, 0, 0, 1);
- free (repo);
-
- b = strrchr (dir, '/');
- if (b == NULL)
- Subdir_Register ((List *) NULL, (char *) NULL, dir);
- else
- {
- *b = '\0';
- Subdir_Register ((List *) NULL, dir, b + 1);
- *b = '/';
- }
- }
+ Create_Admin (dir, dir, repo,
+ (char *)NULL, (char *)NULL, 0, 0, 1);
+ free (repo);
- if (rdirp != NULL)
+ b = strrchr (dir, '/');
+ if (b == NULL)
+ Subdir_Register ((List *) NULL, (char *) NULL, dir);
+ else
{
- /* Skip the slash. */
- ++rdirp;
+ *b = '\0';
+ Subdir_Register ((List *) NULL, dir, b + 1);
+ *b = '/';
}
+ }
- } while (dirp != NULL);
- free (dir);
- /* Now it better work. */
- if ( CVS_CHDIR (dir_name) < 0)
- error (1, errno, "could not chdir to %s", dir_name);
- }
- else if (strcmp (command_name, "export") == 0)
- /* Don't create CVSADM directories if this is export. */
- ;
- else if (!isdir (CVSADM))
- {
- /*
- * Put repository in CVS/Repository. For historical
- * (pre-CVS/Root) reasons, this is an absolute pathname,
- * but what really matters is the part of it which is
- * relative to cvsroot.
- */
- char *repo;
-
- if (reposdirname_absolute)
- repo = reposdirname;
- else
+ if (rdirp != NULL)
{
- repo = xmalloc (strlen (reposdirname)
- + strlen (toplevel_repos)
- + 10);
- strcpy (repo, toplevel_repos);
- strcat (repo, "/");
- strcat (repo, reposdirname);
+ /* Skip the slash. */
+ ++rdirp;
}
- Create_Admin (".", ".", repo, (char *)NULL, (char *)NULL, 0, 1, 1);
- if (repo != reposdirname)
- free (repo);
+ } while (dirp != NULL);
+ free (dir);
+ /* Now it better work. */
+ if ( CVS_CHDIR (dir_name) < 0)
+ error (1, errno, "could not chdir to %s", dir_name);
+ }
+ else if (strcmp (cvs_cmd_name, "export") == 0)
+ /* Don't create CVSADM directories if this is export. */
+ ;
+ else if (!isdir (CVSADM))
+ {
+ /*
+ * Put repository in CVS/Repository. For historical
+ * (pre-CVS/Root) reasons, this is an absolute pathname,
+ * but what really matters is the part of it which is
+ * relative to cvsroot.
+ */
+ char *repo;
+
+ if (reposdirname_absolute)
+ repo = reposdirname;
+ else
+ {
+ repo = xmalloc (strlen (reposdirname)
+ + strlen (toplevel_repos)
+ + 10);
+ strcpy (repo, toplevel_repos);
+ strcat (repo, "/");
+ strcat (repo, reposdirname);
}
- if (strcmp (command_name, "export") != 0)
+ Create_Admin (".", ".", repo, (char *)NULL, (char *)NULL, 0, 1, 1);
+ if (repo != reposdirname)
+ free (repo);
+ }
+
+ if (strcmp (cvs_cmd_name, "export") != 0)
+ {
+ last_entries = Entries_Open (0, dir_name);
+
+ /* If this is a newly created directory, we will record
+ all subdirectory information, so call Subdirs_Known in
+ case there are no subdirectories. If this is not a
+ newly created directory, it may be an old working
+ directory from before we recorded subdirectory
+ information in the Entries file. We force a search for
+ all subdirectories now, to make sure our subdirectory
+ information is up to date. If the Entries file does
+ record subdirectory information, then this call only
+ does list manipulation. */
+ if (newdir)
+ Subdirs_Known (last_entries);
+ else
{
- last_entries = Entries_Open (0, dir_name);
-
- /* If this is a newly created directory, we will record
- all subdirectory information, so call Subdirs_Known in
- case there are no subdirectories. If this is not a
- newly created directory, it may be an old working
- directory from before we recorded subdirectory
- information in the Entries file. We force a search for
- all subdirectories now, to make sure our subdirectory
- information is up to date. If the Entries file does
- record subdirectory information, then this call only
- does list manipulation. */
- if (newdir)
- Subdirs_Known (last_entries);
- else
- {
- List *dirlist;
+ List *dirlist;
- dirlist = Find_Directories ((char *) NULL, W_LOCAL,
- last_entries);
- dellist (&dirlist);
- }
+ dirlist = Find_Directories ((char *) NULL, W_LOCAL,
+ last_entries);
+ dellist (&dirlist);
}
}
- else
- free (dir_name);
free (reposdirname);
(*func) (data, last_entries, short_pathname, filename);
+ if (last_entries != NULL)
+ Entries_Close (last_entries);
+ free (dir_name);
free (short_pathname);
free (reposname);
}
@@ -1798,15 +1867,16 @@ update_entries (data_arg, ent_list, short_pathname, filename)
several causes: (1) something/someone creates the file
during the time that CVS is running, (2) the repository
has two files whose names clash for the client because
- of case-insensitivity or similar causes, (3) a special
- case of this is that a file gets renamed for example
- from a.c to A.C. A "cvs update" on a case-insensitive
- client will get this error. Repeating the update takes
- care of the problem, but is it clear to the user what
- is going on and what to do about it?, (4) the client
- has a file which the server doesn't know about (e.g. "?
- foo" file), and that name clashes with a file the
- server does know about, (5) classify.c will print the same
+ of case-insensitivity or similar causes, See 3 for
+ additional notes. (3) a special case of this is that a
+ file gets renamed for example from a.c to A.C. A
+ "cvs update" on a case-insensitive client will get this
+ error. In this case and in case 2, the filename
+ (short_pathname) printed in the error message will likely _not_
+ have the same case as seen by the user in a directory listing.
+ (4) the client has a file which the server doesn't know
+ about (e.g. "? foo" file), and that name clashes with a file
+ the server does know about, (5) classify.c will print the same
message for other reasons.
I hope the above paragraph makes it clear that making this
@@ -2131,9 +2201,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
struct utimbuf t;
memset (&t, 0, sizeof (t));
- /* There is probably little point in trying to preserved the
- actime (or is there? What about Checked-in?). */
- t.modtime = t.actime = stored_modtime;
+ t.modtime = stored_modtime;
+ (void) time (&t.actime);
#ifdef UTIME_EXPECTS_WRITABLE
if (!iswritable (filename))
@@ -2147,7 +2216,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
error (0, errno, "cannot set time on %s", filename);
#ifdef UTIME_EXPECTS_WRITABLE
- if (change_it_back == 1)
+ if (change_it_back)
{
xchmod (filename, 0);
change_it_back = 0;
@@ -2161,7 +2230,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
* Process the entries line. Do this after we've written the file,
* since we need the timestamp.
*/
- if (strcmp (command_name, "export") != 0)
+ if (strcmp (cvs_cmd_name, "export") != 0)
{
char *local_timestamp;
char *file_timestamp;
@@ -2185,7 +2254,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
{
local_timestamp = file_timestamp;
- /* Checking for command_name of "commit" doesn't seem like
+ /* Checking for cvs_cmd_name of "commit" doesn't seem like
the cleanest way to handle this, but it seem to roughly
parallel what the :local: code which calls
mark_up_to_date ends up amounting to. Some day, should
@@ -2193,7 +2262,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
vis-a-vis both Entries and Base and clarify
cvsclient.texi accordingly. */
- if (!strcmp (command_name, "commit"))
+ if (!strcmp (cvs_cmd_name, "commit"))
mark_up_to_date (filename);
}
@@ -2383,7 +2452,7 @@ handle_set_static_directory (args, len)
char *args;
int len;
{
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
/* Swallow the repository. */
read_line (NULL);
@@ -2408,7 +2477,7 @@ handle_clear_static_directory (pathname, len)
char *pathname;
int len;
{
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
/* Swallow the repository. */
read_line (NULL);
@@ -2463,7 +2532,7 @@ handle_set_sticky (pathname, len)
char *pathname;
int len;
{
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
/* Swallow the repository. */
read_line (NULL);
@@ -2504,7 +2573,7 @@ handle_clear_sticky (pathname, len)
char *pathname;
int len;
{
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
/* Swallow the repository. */
read_line (NULL);
@@ -2533,9 +2602,12 @@ template (data, ent_list, short_pathname, filename)
char *short_pathname;
char *filename;
{
- /* FIXME: should be computing second argument from CVSADM_TEMPLATE
- and short_pathname. */
- read_counted_file (CVSADM_TEMPLATE, "<CVS/Template file>");
+ char *buf = xmalloc ( strlen ( short_pathname )
+ + strlen ( CVSADM_TEMPLATE )
+ + 2 );
+ sprintf ( buf, "%s/%s", short_pathname, CVSADM_TEMPLATE );
+ read_counted_file ( CVSADM_TEMPLATE, buf );
+ free ( buf );
}
static void handle_template PROTO ((char *, int));
@@ -2548,111 +2620,8 @@ handle_template (pathname, len)
call_in_directory (pathname, template, NULL);
}
-
-struct save_prog {
- char *name;
- char *dir;
- struct save_prog *next;
-};
-
-static struct save_prog *checkin_progs;
-static struct save_prog *update_progs;
-
-/*
- * Unlike some responses this doesn't include the repository. So we can't
- * just call call_in_directory and have the right thing happen; we save up
- * the requests and do them at the end.
- */
-static void
-handle_set_checkin_prog (args, len)
- char *args;
- int 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);
- p->name = prog;
- checkin_progs = p;
-}
-
-static void
-handle_set_update_prog (args, len)
- char *args;
- int 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);
- p->name = prog;
- update_progs = p;
-}
-
-static void do_deferred_progs PROTO((void));
-static void
-do_deferred_progs ()
-{
- struct save_prog *p;
- struct save_prog *q;
- char *fname;
- FILE *f;
-
- if (toplevel_wd != NULL)
- {
- if (CVS_CHDIR (toplevel_wd) < 0)
- error (1, errno, "could not chdir to %s", toplevel_wd);
- }
- for (p = checkin_progs; p != NULL; )
- {
- fname = xmalloc (strlen (p->dir) + sizeof CVSADM_CIPROG + 10);
- sprintf (fname, "%s/%s", p->dir, CVSADM_CIPROG);
- f = open_file (fname, "w");
- if (fprintf (f, "%s\n", p->name) < 0)
- error (1, errno, "writing %s", fname);
- if (fclose (f) == EOF)
- error (1, errno, "closing %s", fname);
- free (p->name);
- free (p->dir);
- q = p->next;
- free (p);
- p = q;
- free (fname);
- }
- checkin_progs = NULL;
- for (p = update_progs; p != NULL; )
- {
- fname = xmalloc (strlen (p->dir) + sizeof CVSADM_UPROG + 10);
- sprintf (fname, "%s/%s", p->dir, CVSADM_UPROG);
- f = open_file (fname, "w");
- if (fprintf (f, "%s\n", p->name) < 0)
- error (1, errno, "writing %s", fname);
- if (fclose (f) == EOF)
- error (1, errno, "closing %s", fname);
- free (p->name);
- free (p->dir);
- q = p->next;
- free (p);
- p = q;
- free (fname);
- }
- update_progs = NULL;
-}
-
struct save_dir {
char *dir;
struct save_dir *next;
@@ -2662,7 +2631,7 @@ struct save_dir *prune_candidates;
static void
add_prune_candidate (dir)
- char *dir;
+ const char *dir;
{
struct save_dir *p;
@@ -2719,13 +2688,13 @@ process_prune_candidates ()
static char *last_repos;
static char *last_update_dir;
-static void send_repository PROTO((char *, char *, char *));
+static void send_repository PROTO((const char *, const char *, const char *));
static void
send_repository (dir, repos, update_dir)
- char *dir;
- char *repos;
- char *update_dir;
+ const char *dir;
+ const char *repos;
+ const char *update_dir;
{
char *adm_name;
@@ -2788,7 +2757,7 @@ send_repository (dir, repos, update_dir)
sort of duplicates code elsewhere, but each
case seems slightly different... */
char buf[1];
- char *p = update_dir;
+ const char *p = update_dir;
while (*p != '\0')
{
assert (*p != '\012');
@@ -2855,76 +2824,6 @@ send_repository (dir, repos, update_dir)
error (0, errno, "closing %s", adm_name);
}
}
- if (supported_request ("Checkin-prog"))
- {
- FILE *f;
- if (dir[0] == '\0')
- strcpy (adm_name, CVSADM_CIPROG);
- else
- sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG);
-
- f = CVS_FOPEN (adm_name, "r");
- if (f == NULL)
- {
- if (! existence_error (errno))
- error (1, errno, "reading %s", adm_name);
- }
- else
- {
- char line[80];
- char *nl = NULL;
-
- send_to_server ("Checkin-prog ", 0);
-
- while (fgets (line, sizeof (line), f) != NULL)
- {
- send_to_server (line, 0);
-
- nl = strchr (line, '\n');
- if (nl != NULL)
- break;
- }
- if (nl == NULL)
- send_to_server ("\012", 1);
- if (fclose (f) == EOF)
- error (0, errno, "closing %s", adm_name);
- }
- }
- if (supported_request ("Update-prog"))
- {
- FILE *f;
- if (dir[0] == '\0')
- strcpy (adm_name, CVSADM_UPROG);
- else
- sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG);
-
- f = CVS_FOPEN (adm_name, "r");
- if (f == NULL)
- {
- if (! existence_error (errno))
- error (1, errno, "reading %s", adm_name);
- }
- else
- {
- char line[80];
- char *nl = NULL;
-
- send_to_server ("Update-prog ", 0);
-
- while (fgets (line, sizeof (line), f) != NULL)
- {
- send_to_server (line, 0);
-
- nl = strchr (line, '\n');
- if (nl != NULL)
- break;
- }
- if (nl == NULL)
- send_to_server ("\012", 1);
- if (fclose (f) == EOF)
- error (0, errno, "closing %s", adm_name);
- }
- }
free (adm_name);
if (last_repos != NULL)
free (last_repos);
@@ -2937,11 +2836,13 @@ send_repository (dir, repos, update_dir)
/* Send a Repository line and set toplevel_repos. */
void
-send_a_repository (dir, repository, update_dir)
- char *dir;
- char *repository;
- char *update_dir;
+send_a_repository (dir, repository, update_dir_in)
+ const char *dir;
+ const char *repository;
+ const char *update_dir_in;
{
+ char *update_dir = xstrdup (update_dir_in);
+
if (toplevel_repos == NULL && repository != NULL)
{
if (update_dir[0] == '\0'
@@ -3027,8 +2928,11 @@ send_a_repository (dir, repository, update_dir)
}
send_repository (dir, repository, update_dir);
+ free (update_dir);
}
-
+
+
+
/* The "expanded" modules. */
static int modules_count;
static int modules_allocated;
@@ -3410,10 +3314,6 @@ struct response responses[] =
rs_optional),
RSP_LINE("Template", handle_template, response_type_normal,
rs_optional),
- RSP_LINE("Set-checkin-prog", handle_set_checkin_prog, response_type_normal,
- rs_optional),
- RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal,
- rs_optional),
RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional),
RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal,
rs_optional),
@@ -3442,7 +3342,7 @@ struct response responses[] =
*/
void
send_to_server (str, len)
- char *str;
+ const char *str;
size_t len;
{
static int nbytes;
@@ -3580,6 +3480,8 @@ get_server_responses ()
return 0;
}
+
+
/* Get the responses and then close the connection. */
/*
@@ -3598,14 +3500,20 @@ get_responses_and_close ()
int errs = get_server_responses ();
int status;
- if (last_entries != NULL)
+ /* The following is necessary when working with multiple cvsroots, at least
+ * with commit. It used to be buried nicely in do_deferred_progs() before
+ * that function was removed. I suspect it wouldn't be necessary if
+ * call_in_directory() saved its working directory via save_cwd() before
+ * changing its directory and restored the saved working directory via
+ * restore_cwd() before exiting. Of course, calling CVS_CHDIR only once,
+ * here, may be more efficient.
+ */
+ if( toplevel_wd != NULL )
{
- Entries_Close (last_entries);
- last_entries = NULL;
+ if( CVS_CHDIR( toplevel_wd ) < 0 )
+ error( 1, errno, "could not chdir to %s", toplevel_wd );
}
- do_deferred_progs ();
-
if (client_prune_dirs)
process_prune_candidates ();
@@ -3656,7 +3564,7 @@ supported_request (name)
-#if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS)
+#if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
static struct hostent *init_sockaddr PROTO ((struct sockaddr_in *, char *,
unsigned int));
@@ -3682,12 +3590,8 @@ init_sockaddr (name, hostname, port)
return hostinfo;
}
-#endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) */
-
-#ifdef AUTH_CLIENT_SUPPORT
-
/* Generic function to do port number lookup tasks.
*
* In order of precedence, will return:
@@ -3752,13 +3656,19 @@ get_cvs_port_number (root)
switch (root->method)
{
+# ifdef HAVE_GSSAPI
case gserver_method:
+# endif /* HAVE_GSSAPI */
+# ifdef AUTH_CLIENT_SUPPORT
case pserver_method:
+# endif /* AUTH_CLIENT_SUPPORT */
+# if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI)
return get_port_number ("CVS_CLIENT_PORT", "cvspserver", CVS_AUTH_PORT);
-#ifdef HAVE_KERBEROS
+# endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */
+# ifdef HAVE_KERBEROS
case kserver_method:
return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT);
-#endif
+# endif /* HAVE_KERBEROS */
default:
error(1, EINVAL, "internal error: get_cvs_port_number called for invalid connection method (%s)",
method_names[root->method]);
@@ -3782,7 +3692,7 @@ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock)
FILE *to_server_fp;
FILE *from_server_fp;
-#ifdef NO_SOCKET_TO_FD
+# ifdef NO_SOCKET_TO_FD
if (is_sock)
{
assert (tofd == fromfd);
@@ -3792,7 +3702,7 @@ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock)
(BUFMEMERRPROC) NULL);
}
else
-#endif /* NO_SOCKET_TO_FD */
+# endif /* NO_SOCKET_TO_FD */
{
/* todo: some OS's don't need these calls... */
close_on_exec (tofd);
@@ -3827,43 +3737,11 @@ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock)
(BUFMEMERRPROC) NULL);
}
}
+#endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) || defined(HAVE_GSSAPI) */
-/* Connect to a forked server process. */
-
-void
-connect_to_forked_server (to_server, from_server)
- struct buffer **to_server;
- struct buffer **from_server;
-{
- int tofd, fromfd;
- int child_pid;
-
- /* This is pretty simple. All we need to do is choose the correct
- cvs binary and call piped_child. */
-
- char *command[3];
-
- command[0] = getenv ("CVS_SERVER");
- if (! command[0])
- command[0] = program_path;
-
- command[1] = "server";
- command[2] = NULL;
-
- if (trace)
- {
- fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]);
- }
-
- child_pid = piped_child (command, &tofd, &fromfd);
- if (child_pid < 0)
- error (1, 0, "could not fork server process");
-
- make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
-}
-
+#if defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI)
/* Connect to the authenticating server.
If VERIFY_ONLY is non-zero, then just verify that the password is
@@ -3972,7 +3850,7 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
/* Run the authorization mini-protocol before anything else. */
if (do_gssapi)
{
-#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSAPI
FILE *fp = stdio_buffer_get_file(lto_server);
int fd = fp ? fileno(fp) : -1;
struct stat s;
@@ -3988,12 +3866,13 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
"authorization failed: server %s rejected access to %s",
root->hostname, root->directory);
}
-#else
- error (1, 0, "This client does not support GSSAPI authentication");
-#endif
+# else /* ! HAVE_GSSAPI */
+ error (1, 0, "INTERNAL ERROR: This client does not support GSSAPI authentication");
+# endif /* HAVE_GSSAPI */
}
- else
+ else /* ! do_gssapi */
{
+# ifdef AUTH_CLIENT_SUPPORT
char *begin = NULL;
char *password = NULL;
char *end = NULL;
@@ -4039,7 +3918,10 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
/* Paranoia. */
memset (password, 0, strlen (password));
- }
+# else /* ! AUTH_CLIENT_SUPPORT */
+ error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication");
+# endif /* AUTH_CLIENT_SUPPORT */
+ } /* if (do_gssapi) */
{
char *read_buf;
@@ -4114,12 +3996,53 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
}
}
}
-#endif /* AUTH_CLIENT_SUPPORT */
+#endif /* defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) */
-#ifdef HAVE_KERBEROS
+#ifdef CLIENT_SUPPORT
+/* void
+ * connect_to_forked_server ( struct buffer **to_server,
+ * struct buffer **from_server )
+ *
+ * Connect to a forked server process.
+ */
+void
+connect_to_forked_server (to_server, from_server)
+ struct buffer **to_server;
+ struct buffer **from_server;
+{
+ int tofd, fromfd;
+ int child_pid;
+
+ /* This is pretty simple. All we need to do is choose the correct
+ cvs binary and call piped_child. */
+
+ const char *command[3];
+
+ command[0] = getenv ("CVS_SERVER");
+ if (! command[0])
+ command[0] = program_path;
+
+ command[1] = "server";
+ command[2] = NULL;
+
+ if (trace)
+ {
+ fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]);
+ }
+ child_pid = piped_child (command, &tofd, &fromfd);
+ if (child_pid < 0)
+ error (1, 0, "could not fork server process");
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
+}
+#endif /* CLIENT_SUPPORT */
+
+
+
+#ifdef HAVE_KERBEROS
/* This function has not been changed to deal with NO_SOCKET_TO_FD
(i.e., systems on which sockets cannot be converted to file
descriptors). The first person to try building a kerberos client
@@ -4146,8 +4069,7 @@ start_tcp_server (root, to_server, from_server)
hp = init_sockaddr (&sin, root->hostname, port);
- hname = xmalloc (strlen (hp->h_name) + 1);
- strcpy (hname, hp->h_name);
+ hname = xstrdup (hp->h_name);
if (trace)
{
@@ -4348,6 +4270,8 @@ connect_to_gserver (root, sock, hostinfo)
#endif /* HAVE_GSSAPI */
+
+
static int send_variable_proc PROTO ((Node *, void *));
static int
@@ -4363,6 +4287,8 @@ send_variable_proc (node, closure)
return 0;
}
+
+
/* Contact the server. */
void
start_server ()
@@ -4375,7 +4301,6 @@ start_server ()
free (toplevel_repos);
toplevel_repos = NULL;
-
/* Note that generally speaking we do *not* fall back to a different
way of connecting if the first one does not work. This is slow
(*really* slow on a 14.4kbps link); the clean way to have a CVS
@@ -4391,32 +4316,32 @@ start_server ()
*/
connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 0);
break;
-#endif
+#endif /* AUTH_CLIENT_SUPPORT */
#if HAVE_KERBEROS
case kserver_method:
start_tcp_server (current_parsed_root, &to_server, &from_server);
break;
-#endif
+#endif /* HAVE_KERBEROS */
#ifdef HAVE_GSSAPI
case gserver_method:
/* GSSAPI authentication is handled by the pserver. */
connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 1);
break;
-#endif
+#endif /* HAVE_GSSAPI */
case ext_method:
-#if defined (NO_EXT_METHOD)
+#ifdef NO_EXT_METHOD
error (0, 0, ":ext: method not supported by this port of CVS");
error (1, 0, "try :server: instead");
-#else
+#else /* ! NO_EXT_METHOD */
start_rsh_server (current_parsed_root, &to_server, &from_server);
-#endif
+#endif /* NO_EXT_METHOD */
break;
case server_method:
-#if defined(START_SERVER)
+#ifdef START_SERVER
{
int tofd, fromfd;
START_SERVER (&tofd, &fromfd, getcaller (),
@@ -4424,17 +4349,17 @@ start_server ()
current_parsed_root->directory);
# ifdef START_SERVER_RETURNS_SOCKET
make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 1);
-# else
+# else /* ! START_SERVER_RETURNS_SOCKET */
make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 0);
# endif /* START_SERVER_RETURNS_SOCKET */
}
-#else
+#else /* ! START_SERVER */
/* FIXME: It should be possible to implement this portably,
like pserver, which would get rid of the duplicated code
in {vms,windows-NT,...}/startserver.c. */
error (1, 0,
"the :server: access method is not supported by this port of CVS");
-#endif
+#endif /* START_SERVER */
break;
case fork_method:
@@ -4495,9 +4420,6 @@ start_server ()
if (toplevel_repos != NULL)
free (toplevel_repos);
toplevel_repos = NULL;
- if (last_dir_name != NULL)
- free (last_dir_name);
- last_dir_name = NULL;
if (last_repos != NULL)
free (last_repos);
last_repos = NULL;
@@ -4511,7 +4433,7 @@ start_server ()
stored_mode = NULL;
}
- rootless = (strcmp (command_name, "init") == 0);
+ rootless = (strcmp (cvs_cmd_name, "init") == 0);
if (!rootless)
{
send_to_server ("Root ", 0);
@@ -4603,16 +4525,6 @@ start_server ()
error (1, 0,
"This server does not support the global -t option.");
}
- if (logoff)
- {
- if (have_global)
- {
- send_to_server ("Global_option -l\012", 0);
- }
- else
- error (1, 0,
- "This server does not support the global -l option.");
- }
}
/* Find out about server-side cvswrappers. An extra network
@@ -4623,8 +4535,8 @@ start_server ()
reason to bother would be so we could make add work without
contacting the server, I suspect). */
- if ((strcmp (command_name, "import") == 0)
- || (strcmp (command_name, "add") == 0))
+ if ((strcmp (cvs_cmd_name, "import") == 0)
+ || (strcmp (cvs_cmd_name, "add") == 0))
{
if (supported_request ("wrapper-sendme-rcsOptions"))
{
@@ -4755,11 +4667,6 @@ start_server ()
#endif /* ! HAVE_GSSAPI */
}
-#ifdef FILENAMES_CASE_INSENSITIVE
- if (supported_request ("Case") && !rootless)
- send_to_server ("Case\012", 0);
-#endif
-
/* If "Set" is not supported, just silently fail to send the variables.
Users with an old server should get a useful error message when it
fails to recognize the ${=foo} syntax. This way if someone uses
@@ -4769,6 +4676,8 @@ start_server ()
walklist (variable_list, send_variable_proc, NULL);
}
+
+
#ifndef NO_EXT_METHOD
/* Contact the server by starting it with rsh. */
@@ -4905,8 +4814,8 @@ start_rsh_server (root, to_server, from_server)
sprintf (command, "%s server", cvs_server);
{
- char *argv[10];
- char **p = argv;
+ const char *argv[10];
+ const char **p = argv;
*p++ = cvs_rsh;
*p++ = root->hostname;
@@ -4973,8 +4882,10 @@ send_arg (string)
}
send_to_server ("\012", 1);
}
-
-static void send_modified PROTO ((char *, char *, Vers_TS *));
+
+
+
+static void send_modified PROTO ((const char *, const char *, Vers_TS *));
/* VERS->OPTIONS specifies whether the file is binary or not. NOTE: BEFORE
using any other fields of the struct vers, we would need to fix
@@ -4982,8 +4893,8 @@ static void send_modified PROTO ((char *, char *, Vers_TS *));
static void
send_modified (file, short_pathname, vers)
- char *file;
- char *short_pathname;
+ const char *file;
+ const char *short_pathname;
Vers_TS *vers;
{
/* File was modified, send it. */
@@ -5149,7 +5060,7 @@ send_fileproc (callerdat, finfo)
struct file_info xfinfo;
/* File name to actually use. Might differ in case from
finfo->file. */
- char *filename;
+ const char *filename;
send_a_repository ("", finfo->repository, finfo->update_dir);
@@ -5291,12 +5202,14 @@ warning: ignoring -k options due to server limitations");
return 0;
}
-static void send_ignproc PROTO ((char *, char *));
+
+
+static void send_ignproc PROTO ((const char *, const char *));
static void
send_ignproc (file, dir)
- char *file;
- char *dir;
+ const char *file;
+ const char *dir;
{
if (ign_inhibit_server || !supported_request ("Questionable"))
{
@@ -5313,14 +5226,17 @@ send_ignproc (file, dir)
}
}
-static int send_filesdoneproc PROTO ((void *, int, char *, char *, List *));
+
+
+static int send_filesdoneproc PROTO ((void *, int, const char *, const char *,
+ List *));
static int
send_filesdoneproc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
/* if this directory has an ignore list, process it then free it */
@@ -5333,7 +5249,8 @@ send_filesdoneproc (callerdat, err, repository, update_dir, entries)
return (err);
}
-static Dtype send_dirent_proc PROTO ((void *, char *, char *, char *, List *));
+static Dtype send_dirent_proc PROTO ((void *, const char *, const char *,
+ const char *, List *));
/*
* send_dirent_proc () is called back by the recursion processor before a
@@ -5346,9 +5263,9 @@ static Dtype send_dirent_proc PROTO ((void *, char *, char *, char *, List *));
static Dtype
send_dirent_proc (callerdat, dir, repository, update_dir, entries)
void *callerdat;
- char *dir;
- char *repository;
- char *update_dir;
+ const char *dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
struct send_data *args = (struct send_data *) callerdat;
@@ -5418,7 +5335,10 @@ 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 *));
+
+
+static int send_dirleave_proc PROTO ((void *, const char *, int, const char *,
+ List *));
/*
* send_dirleave_proc () is called back by the recursion code upon leaving
@@ -5429,9 +5349,9 @@ static int send_dirleave_proc PROTO ((void *, char *, int, char *, List *));
static int
send_dirleave_proc (callerdat, dir, err, update_dir, entries)
void *callerdat;
- char *dir;
+ const char *dir;
int err;
- char *update_dir;
+ const char *update_dir;
List *entries;
{
@@ -5475,8 +5395,8 @@ send_option_string (string)
}
-/* Send the names of all the argument files to the server. */
+/* Send the names of all the argument files to the server. */
void
send_file_names (argc, argv, flags)
int argc;
@@ -5484,89 +5404,116 @@ send_file_names (argc, argv, flags)
unsigned int flags;
{
int i;
- int level;
- int max_level;
/* The fact that we do this here as well as start_recursion is a bit
of a performance hit. Perhaps worth cleaning up someday. */
if (flags & SEND_EXPAND_WILD)
expand_wild (argc, argv, &argc, &argv);
- /* Send Max-dotdot if needed. */
- max_level = 0;
- for (i = 0; i < argc; ++i)
- {
- level = pathname_levels (argv[i]);
- if (level > max_level)
- max_level = level;
- }
- if (max_level > 0)
- {
- if (supported_request ("Max-dotdot"))
- {
- char buf[10];
- sprintf (buf, "%d", max_level);
-
- send_to_server ("Max-dotdot ", 0);
- send_to_server (buf, 0);
- send_to_server ("\012", 1);
- }
- else
- /*
- * "leading .." is not strictly correct, as this also includes
- * cases like "foo/../..". But trying to explain that in the
- * error message would probably just confuse users.
- */
- error (1, 0,
- "leading .. not supported by old (pre-Max-dotdot) servers");
- }
-
for (i = 0; i < argc; ++i)
{
char buf[1];
- char *p = argv[i];
- char *line = NULL;
+ char *p;
+#ifdef FILENAMES_CASE_INSENSITIVE
+ char *line = xmalloc (1);
+ *line = '\0';
+#endif /* FILENAMES_CASE_INSENSITIVE */
if (arg_should_not_be_sent_to_server (argv[i]))
continue;
#ifdef FILENAMES_CASE_INSENSITIVE
- /* We want to send the file name as it appears
- in CVS/Entries. We put this inside an ifdef
+ /* We want to send the path as it appears in the
+ CVS/Entries files. We put this inside an ifdef
to avoid doing all these system calls in
cases where fncmp is just strcmp anyway. */
- /* For now just do this for files in the local
- directory. Would be nice to handle the
- non-local case too, though. */
- /* The isdir check could more gracefully be replaced
+ /* The isdir (CVSADM) check could more gracefully be replaced
with a way of having Entries_Open report back the
error to us and letting us ignore existence_error.
Or some such. */
- if (p == last_component (p) && isdir (CVSADM))
{
- List *entries;
- Node *node;
-
- /* If we were doing non-local directory,
- we would save_cwd, CVS_CHDIR
- like in update.c:isemptydir. */
- /* Note that if we are adding a directory,
- the following will read the entry
- that we just wrote there, that is, we
- will get the case specified on the
- command line, not the case of the
- directory in the filesystem. This
- is correct behavior. */
- entries = Entries_Open (0, NULL);
- node = findnode_fn (entries, p);
- if (node != NULL)
+ List *stack;
+ size_t line_len = 0;
+ char *q, *r;
+ struct saved_cwd sdir;
+
+ /* Split the argument onto the stack. */
+ stack = getlist();
+ r = xstrdup (argv[i]);
+ /* It's okay to discard the const from the last_component return
+ * below since we know we passed in an arg that was not const.
+ */
+ while ((q = (char *)last_component (r)) != r)
{
- line = xstrdup (node->key);
- p = line;
- delnode (node);
+ push (stack, xstrdup (q));
+ *--q = '\0';
}
- Entries_Close (entries);
+ push (stack, r);
+
+ /* Normalize the path into outstr. */
+ save_cwd (&sdir);
+ while (q = pop (stack))
+ {
+ Node *node = NULL;
+ if (isdir (CVSADM))
+ {
+ List *entries;
+
+ /* Note that if we are adding a directory,
+ the following will read the entry
+ that we just wrote there, that is, we
+ will get the case specified on the
+ command line, not the case of the
+ directory in the filesystem. This
+ is correct behavior. */
+ entries = Entries_Open (0, NULL);
+ node = findnode_fn (entries, q);
+ if (node != NULL)
+ {
+ /* Add the slash unless this is our first element. */
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, node->key);
+ delnode (node);
+ }
+ Entries_Close (entries);
+ }
+
+ /* If node is still NULL then we either didn't find CVSADM or
+ * we didn't find an entry there.
+ */
+ if (node == NULL)
+ {
+ /* Add the slash unless this is our first element. */
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, q);
+ break;
+ }
+
+ /* And descend the tree. */
+ if (isdir (q))
+ CVS_CHDIR (q);
+ free (q);
+ }
+ restore_cwd (&sdir, NULL);
+ free_cwd (&sdir);
+
+ /* Now put everything we didn't find entries for back on. */
+ while (q = pop (stack))
+ {
+ if (line_len)
+ xrealloc_and_strcat (&line, &line_len, "/");
+ xrealloc_and_strcat (&line, &line_len, q);
+ free (q);
+ }
+
+ p = line;
+
+ dellist (&stack);
}
+#else /* !FILENAMES_CASE_INSENSITIVE */
+ p = argv[i];
#endif /* FILENAMES_CASE_INSENSITIVE */
send_to_server ("Argument ", 0);
@@ -5590,8 +5537,9 @@ send_file_names (argc, argv, flags)
++p;
}
send_to_server ("\012", 1);
- if (line != NULL)
- free (line);
+#ifdef FILENAMES_CASE_INSENSITIVE
+ free (line);
+#endif /* FILENAMES_CASE_INSENSITIVE */
}
if (flags & SEND_EXPAND_WILD)
@@ -5604,6 +5552,51 @@ send_file_names (argc, argv, flags)
}
+
+/* Calculate and send max-dotdot to the server */
+static void
+send_max_dotdot (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ int level = 0;
+ int max_level = 0;
+
+ /* Send Max-dotdot if needed. */
+ for (i = 0; i < argc; ++i)
+ {
+ level = pathname_levels (argv[i]);
+ if (level > 0)
+ {
+ if (uppaths == NULL) uppaths = getlist();
+ push_string (uppaths, xstrdup (argv[i]));
+ }
+ if (level > max_level)
+ max_level = level;
+ }
+
+ if (max_level > 0)
+ {
+ if (supported_request ("Max-dotdot"))
+ {
+ char buf[10];
+ sprintf (buf, "%d", max_level);
+
+ send_to_server ("Max-dotdot ", 0);
+ send_to_server (buf, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ {
+ error (1, 0,
+"backreference in path (`..') not supported by old (pre-Max-dotdot) servers");
+ }
+ }
+}
+
+
+
/* Send Repository, Modified and Entry. argc and argv contain only
the files to operate on (or empty for everything), not options.
local is nonzero if we should not recurse (-l option). flags &
@@ -5624,6 +5617,8 @@ send_files (argc, argv, local, aflag, flags)
struct send_data args;
int err;
+ send_max_dotdot (argc, argv);
+
/*
* aflag controls whether the tag/date is copied into the vers_ts.
* But we don't actually use it, so I don't think it matters what we pass
@@ -5636,7 +5631,8 @@ send_files (argc, argv, local, aflag, flags)
err = start_recursion
(send_fileproc, send_filesdoneproc,
send_dirent_proc, send_dirleave_proc, (void *) &args,
- argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE, (char *)NULL, 0);
+ argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE, (char *) NULL, 0,
+ (char *) NULL);
if (err)
error_exit ();
if (toplevel_repos == NULL)
@@ -5769,7 +5765,9 @@ client_import_done ()
toplevel_repos = xstrdup (current_parsed_root->directory);
send_repository ("", toplevel_repos, ".");
}
-
+
+
+
static void
notified_a_file (data, ent_list, short_pathname, filename)
char *data;
@@ -5888,11 +5886,11 @@ handle_notified (args, len)
void
client_notify (repository, update_dir, filename, notif_type, val)
- char *repository;
- char *update_dir;
- char *filename;
+ const char *repository;
+ const char *update_dir;
+ const char *filename;
int notif_type;
- char *val;
+ const char *val;
{
char buf[2];
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 6408f21..4a5b1fb 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -22,40 +22,44 @@
#include "fileattr.h"
#include "hardlink.h"
-static Dtype check_direntproc PROTO ((void *callerdat, char *dir,
- char *repos, char *update_dir,
- List *entries));
+static Dtype check_direntproc PROTO ((void *callerdat, const char *dir,
+ const char *repos,
+ const char *update_dir,
+ List *entries));
static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int check_filesdoneproc PROTO ((void *callerdat, int err,
- char *repos, char *update_dir,
- List *entries));
-static int checkaddfile PROTO((char *file, char *repository, char *tag,
- char *options, RCSNode **rcsnode));
-static Dtype commit_direntproc PROTO ((void *callerdat, char *dir,
- char *repos, char *update_dir,
- List *entries));
-static int commit_dirleaveproc PROTO ((void *callerdat, char *dir,
- int err, char *update_dir,
- List *entries));
+ const char *repos,
+ const char *update_dir,
+ List *entries));
+static int checkaddfile PROTO((const char *file, const char *repository,
+ const char *tag, const char *options,
+ RCSNode **rcsnode));
+static Dtype commit_direntproc PROTO ((void *callerdat, const char *dir,
+ const char *repos,
+ const char *update_dir,
+ List *entries));
+static int commit_dirleaveproc PROTO ((void *callerdat, const char *dir,
+ int err, const char *update_dir,
+ List *entries));
static int commit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int commit_filesdoneproc PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
+ const char *repository,
+ const char *update_dir,
+ List *entries));
static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag,
char *options));
static int findmaxrev PROTO((Node * p, void *closure));
-static int lock_RCS PROTO((char *user, RCSNode *rcs, char *rev,
- char *repository));
+static int lock_RCS PROTO((const char *user, RCSNode *rcs, const char *rev,
+ const char *repository));
static int precommit_list_proc PROTO((Node * p, void *closure));
-static int precommit_proc PROTO((char *repository, char *filter));
+static int precommit_proc PROTO((const char *repository, const char *filter));
static int remove_file PROTO ((struct file_info *finfo, char *tag,
char *message));
-static void fixaddfile PROTO((char *file, char *repository));
+static void fixaddfile PROTO((const char *rcs));
static void fixbranch PROTO((RCSNode *, char *branch));
static void unlockrcs PROTO((RCSNode *rcs));
static void ci_delproc PROTO((Node *p));
static void masterlist_delproc PROTO((Node *p));
-static char *locate_rcs PROTO((char *file, char *repository));
struct commit_info
{
@@ -72,7 +76,6 @@ struct master_lists
static int force_ci = 0;
static int got_message;
-static int run_module_prog = 1;
static int aflag;
static char *saved_tag;
static char *write_dirtag;
@@ -85,8 +88,7 @@ static time_t last_register_time;
static const char *const commit_usage[] =
{
- "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n",
- " -n Do not run the module program (if any).\n",
+ "Usage: %s %s [-Rlf] [-m msg | -F logfile] [-r rev] files...\n",
" -R Process directories recursively.\n",
" -l Local directory only (not recursive).\n",
" -f Force the file to be committed; disables recursion.\n",
@@ -125,23 +127,26 @@ struct find_data {
/* Only good within functions called from the filesdoneproc. Stores
the repository (pointer into storage managed by the recursion
processor. */
- char *repository;
+ const char *repository;
/* Non-zero if we should force the commit. This is enabled by
either -f or -r options, unlike force_ci which is just -f. */
int force;
};
-static Dtype find_dirent_proc PROTO ((void *callerdat, char *dir,
- char *repository, char *update_dir,
- List *entries));
+
+
+static Dtype find_dirent_proc PROTO ((void *callerdat, const char *dir,
+ const char *repository,
+ const char *update_dir,
+ List *entries));
static Dtype
find_dirent_proc (callerdat, dir, repository, update_dir, entries)
void *callerdat;
- char *dir;
- char *repository;
- char *update_dir;
+ const char *dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
struct find_data *find_data = (struct find_data *)callerdat;
@@ -165,16 +170,20 @@ find_dirent_proc (callerdat, dir, repository, update_dir, entries)
return R_PROCESS;
}
+
+
/* Here as a static until we get around to fixing ignore_files to pass
it along as an argument. */
static struct find_data *find_data_static;
-static void find_ignproc PROTO ((char *, char *));
+
+
+static void find_ignproc PROTO ((const char *, const char *));
static void
find_ignproc (file, dir)
- char *file;
- char *dir;
+ const char *file;
+ const char *dir;
{
struct question *p;
@@ -186,16 +195,19 @@ find_ignproc (file, dir)
find_data_static->questionables = p;
}
+
+
static int find_filesdoneproc PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
+ const char *repository,
+ const char *update_dir,
+ List *entries));
static int
find_filesdoneproc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
struct find_data *find_data = (struct find_data *)callerdat;
@@ -259,27 +271,43 @@ find_fileproc (callerdat, finfo)
freevers_ts (&vers);
return 1;
}
- if (vers->ts_user == NULL)
+ if (vers->vn_user[0] == '-')
+ {
+ if (vers->ts_user != NULL)
+ {
+ error (0, 0,
+ "`%s' should be removed and is still there (or is back"
+ " again)", finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+ /* else */
+ status = T_REMOVED;
+ }
+ else if (strcmp (vers->vn_user, "0") == 0)
{
- if (strcmp (vers->vn_user, "0") == 0)
+ if (vers->ts_user == NULL)
+ {
/* This happens when one has `cvs add'ed a file, but it no
longer exists in the working directory at commit time.
FIXME: What classify_file does in this case is print
"new-born %s has disappeared" and removes the entry.
We probably should do the same. */
- status = T_ADDED;
- else if (vers->vn_user[0] == '-')
- status = T_REMOVED;
- else
- {
- /* FIXME: What classify_file does in this case is print
- "%s was lost". We probably should do the same. */
- freevers_ts (&vers);
- return 0;
+ if (!really_quiet)
+ error (0, 0, "warning: new-born %s has disappeared",
+ finfo->fullname);
+ status = T_REMOVE_ENTRY;
}
+ else
+ status = T_ADDED;
+ }
+ else if (vers->ts_user == NULL)
+ {
+ /* FIXME: What classify_file does in this case is print
+ "%s was lost". We probably should do the same. */
+ freevers_ts (&vers);
+ return 0;
}
- else if (strcmp (vers->vn_user, "0") == 0)
- status = T_ADDED;
else if (vers->ts_rcs != NULL
&& (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
/* If we are forcing commits, pretend that the file is
@@ -305,7 +333,7 @@ find_fileproc (callerdat, finfo)
node->type = UPDATE;
node->delproc = update_delproc;
- node->data = (char *) data;
+ node->data = data;
(void)addnode (args->ulist, node);
++args->argc;
@@ -327,6 +355,11 @@ copy_ulist (node, data)
}
#endif /* CLIENT_SUPPORT */
+#ifdef SERVER_SUPPORT
+# define COMMIT_OPTIONS "+nlRm:fF:r:"
+#else /* !SERVER_SUPPORT */
+# define COMMIT_OPTIONS "+lRm:fF:r:"
+#endif /* SERVER_SUPPORT */
int
commit (argc, argv)
int argc;
@@ -365,13 +398,17 @@ commit (argc, argv)
#endif /* CVS_BADROOT */
optind = 0;
- while ((c = getopt (argc, argv, "+nlRm:fF:r:")) != -1)
+ while( ( c = getopt( argc, argv, COMMIT_OPTIONS ) ) != -1 )
{
switch (c)
{
+#ifdef SERVER_SUPPORT
case 'n':
- run_module_prog = 0;
+ /* Silently ignore -n for compatibility with old
+ * clients.
+ */
break;
+#endif /* SERVER_SUPPORT */
case 'm':
#ifdef FORCE_USE_EDITOR
use_editor = 1;
@@ -426,7 +463,8 @@ commit (argc, argv)
/* strip trailing dots and leading zeros */
while (*--p == '.') ;
p[1] = '\0';
- while (*saved_tag == '0') ++saved_tag;
+ while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1]))
+ ++saved_tag;
}
/* some checks related to the "-F logfile" option */
@@ -463,7 +501,7 @@ commit (argc, argv)
find_dirent_proc, (DIRLEAVEPROC) NULL,
(void *)&find_args,
argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
- (char *)NULL, 0);
+ (char *) NULL, 0, (char *) NULL);
if (err)
error (1, 0, "correct above errors first!");
@@ -552,8 +590,6 @@ commit (argc, argv)
send_arg("-l");
if (force_ci)
send_arg("-f");
- if (!run_module_prog)
- send_arg("-n");
option_with_arg ("-r", saved_tag);
send_arg ("--");
@@ -644,7 +680,7 @@ commit (argc, argv)
err = start_recursion (check_fileproc, check_filesdoneproc,
check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc,
argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
- (char *) NULL, 1);
+ (char *) NULL, 1, (char *) NULL);
if (err)
{
Lock_Cleanup ();
@@ -659,7 +695,7 @@ commit (argc, argv)
err = start_recursion (commit_fileproc, commit_filesdoneproc,
commit_direntproc, commit_dirleaveproc, NULL,
argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
- (char *) NULL, 1);
+ (char *) NULL, 1, (char *) NULL);
/*
* Unlock all the dirs and clean up
@@ -779,7 +815,7 @@ check_fileproc (callerdat, finfo)
struct file_info *finfo;
{
Ctype status;
- char *xdir;
+ const char *xdir;
Node *p;
List *ulist, *cilist;
Vers_TS *vers;
@@ -833,7 +869,8 @@ check_fileproc (callerdat, finfo)
* - can't have a sticky date
* - can't have a sticky tag that is not a branch
* Also,
- * - if status is T_REMOVED, can't have a numeric tag
+ * - if status is T_REMOVED, file must not exist and its entry
+ * can't have a numeric sticky tag.
* - if status is T_ADDED, rcs file must not exist unless on
* a branch or head is dead
* - if status is T_ADDED, can't have a non-trunk numeric rev
@@ -863,29 +900,13 @@ check_fileproc (callerdat, finfo)
}
if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
{
- char *filestamp;
- int retcode;
-
/*
* We found a "conflict" marker.
*
* If the timestamp on the file is the same as the
* timestamp stored in the Entries file, we block the commit.
*/
-#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);
- }
-#else
- filestamp = time_stamp (finfo->file);
- retcode = strcmp (vers->ts_conflict, filestamp);
- free (filestamp);
-#endif
- if (retcode == 0)
+ if ( file_has_conflict ( finfo, vers->ts_conflict ) )
{
error (0, 0,
"file `%s' had a conflict and has not been modified",
@@ -913,20 +934,30 @@ warning: file `%s' seems to still contain conflict indicators",
}
}
- if (status == T_REMOVED
- && vers->tag
- && isdigit ((unsigned char) *vers->tag))
+ if (status == T_REMOVED)
{
- /* Remove also tries to forbid this, but we should check
- here. I'm only _sure_ about somewhat obscure cases
- (hacking the Entries file, using an old version of
- CVS for the remove and a new one for the commit), but
- there might be other cases. */
- error (0, 0,
- "cannot remove file `%s' which has a numeric sticky tag of `%s'",
- finfo->fullname, vers->tag);
- freevers_ts (&vers);
- return (1);
+ if (vers->ts_user != NULL)
+ {
+ error (0, 0,
+ "`%s' should be removed and is still there (or is"
+ " back again)", finfo->fullname);
+ freevers_ts (&vers);
+ return 1;
+ }
+
+ if (vers->tag && isdigit ((unsigned char) *vers->tag))
+ {
+ /* Remove also tries to forbid this, but we should check
+ here. I'm only _sure_ about somewhat obscure cases
+ (hacking the Entries file, using an old version of
+ CVS for the remove and a new one for the commit), but
+ there might be other cases. */
+ error (0, 0,
+ "cannot remove file `%s' which has a numeric sticky"
+ " tag of `%s'", finfo->fullname, vers->tag);
+ freevers_ts (&vers);
+ return (1);
+ }
}
if (status == T_ADDED)
{
@@ -976,7 +1007,7 @@ warning: file `%s' seems to still contain conflict indicators",
xmalloc (sizeof (struct master_lists));
ml->ulist = ulist;
ml->cilist = cilist;
- p->data = (char *) ml;
+ p->data = ml;
p->delproc = masterlist_delproc;
(void) addnode (mulist, p);
}
@@ -992,7 +1023,7 @@ warning: file `%s' seems to still contain conflict indicators",
li->tag = xstrdup (vers->tag);
li->rev_old = xstrdup (vers->vn_rcs);
li->rev_new = NULL;
- p->data = (char *) li;
+ p->data = li;
(void) addnode (ulist, p);
p = getnode ();
@@ -1010,7 +1041,7 @@ warning: file `%s' seems to still contain conflict indicators",
ci->rev = (char *) NULL;
ci->tag = xstrdup (vers->tag);
ci->options = xstrdup(vers->options);
- p->data = (char *) ci;
+ p->data = ci;
(void) addnode (cilist, p);
#ifdef PRESERVE_PERMISSIONS_SUPPORT
@@ -1043,7 +1074,7 @@ warning: file `%s' seems to still contain conflict indicators",
hlinfo = (struct hardlink_info *)
xmalloc (sizeof (struct hardlink_info));
hlinfo->status = status;
- linkp->data = (char *) hlinfo;
+ linkp->data = hlinfo;
}
}
#endif
@@ -1064,6 +1095,8 @@ warning: file `%s' seems to still contain conflict indicators",
return (0);
}
+
+
/*
* By default, return the code that tells do_recursion to examine all
* directories
@@ -1072,9 +1105,9 @@ warning: file `%s' seems to still contain conflict indicators",
static Dtype
check_direntproc (callerdat, dir, repos, update_dir, entries)
void *callerdat;
- char *dir;
- char *repos;
- char *update_dir;
+ const char *dir;
+ const char *repos;
+ const char *update_dir;
List *entries;
{
if (!isdir (dir))
@@ -1094,9 +1127,7 @@ precommit_list_proc (p, closure)
Node *p;
void *closure;
{
- struct logfile_info *li;
-
- li = (struct logfile_info *) p->data;
+ struct logfile_info *li = p->data;
if (li->type == T_ADDED
|| li->type == T_MODIFIED
|| li->type == T_REMOVED)
@@ -1111,8 +1142,8 @@ precommit_list_proc (p, closure)
*/
static int
precommit_proc (repository, filter)
- char *repository;
- char *filter;
+ const char *repository;
+ const char *filter;
{
/* see if the filter is there, only if it's a full path */
if (isabsolute (filter))
@@ -1149,8 +1180,8 @@ static int
check_filesdoneproc (callerdat, err, repos, update_dir, entries)
void *callerdat;
int err;
- char *repos;
- char *update_dir;
+ const char *repos;
+ const char *update_dir;
List *entries;
{
int n;
@@ -1245,7 +1276,7 @@ commit_fileproc (callerdat, finfo)
if (p == NULL)
return (0);
- ci = (struct commit_info *) p->data;
+ ci = p->data;
if (ci->status == T_MODIFIED)
{
if (finfo->rcs == NULL)
@@ -1263,7 +1294,8 @@ commit_fileproc (callerdat, finfo)
if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
&finfo->rcs) != 0)
{
- fixaddfile (finfo->file, finfo->repository);
+ if (finfo->rcs != NULL)
+ fixaddfile (finfo->rcs->path);
err = 1;
goto out;
}
@@ -1283,7 +1315,7 @@ commit_fileproc (callerdat, finfo)
if (ci->rev)
free (ci->rev);
ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
- err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
+ err = Checkin ('A', finfo, ci->rev,
ci->tag, ci->options, saved_message);
if (err != 0)
{
@@ -1328,8 +1360,7 @@ commit_fileproc (callerdat, finfo)
}
else if (ci->status == T_MODIFIED)
{
- err = Checkin ('M', finfo,
- finfo->rcs->path, ci->rev, ci->tag,
+ err = Checkin ('M', finfo, ci->rev, ci->tag,
ci->options, saved_message);
(void) time (&last_register_time);
@@ -1377,7 +1408,7 @@ out:
copy it into the log information (see logmsg.c
(logfile_write) for more details). We should only update
the version number for files that have been added or
- modified but not removed. Why? classify_file_internal
+ modified but not removed since classify_file_internal
will return the version number of a file even after it has
been removed from the archive, which is not the behavior we
want for our commitlog messages; we want the old version
@@ -1392,7 +1423,7 @@ out:
struct logfile_info *li;
(void) classify_file_internal (finfo, &vers);
- li = (struct logfile_info *) p->data;
+ li = p->data;
li->rev_new = xstrdup (vers->vn_rcs);
freevers_ts (&vers);
}
@@ -1412,8 +1443,8 @@ static int
commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
Node *p;
@@ -1427,12 +1458,11 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
got_message = 0;
-
Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
/* Build the administrative files if necessary. */
{
- char *p;
+ const char *p;
if (strncmp (current_parsed_root->directory, repository,
strlen (current_parsed_root->directory)) != 0)
@@ -1465,63 +1495,13 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
cvs_output (program_name, 0);
cvs_output (" ", 1);
- cvs_output (command_name, 0);
+ cvs_output (cvs_cmd_name, 0);
cvs_output (": Rebuilding administrative file database\n", 0);
mkmodules (admin_dir);
free (admin_dir);
}
}
- if (err == 0 && run_module_prog)
- {
- FILE *fp;
-
- if ((fp = CVS_FOPEN (CVSADM_CIPROG, "r")) != NULL)
- {
- char *line;
- int line_length;
- size_t line_chars_allocated;
- char *repos;
-
- line = NULL;
- line_chars_allocated = 0;
- line_length = getline (&line, &line_chars_allocated, fp);
- if (line_length > 0)
- {
- /* Remove any trailing newline. */
- if (line[line_length - 1] == '\n')
- line[--line_length] = '\0';
- repos = Name_Repository ((char *) NULL, update_dir);
- run_setup (line);
- run_arg (repos);
- cvs_output (program_name, 0);
- cvs_output (" ", 1);
- cvs_output (command_name, 0);
- 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);
- }
- else
- {
- if (ferror (fp))
- error (0, errno, "warning: error reading %s",
- CVSADM_CIPROG);
- }
- if (line != NULL)
- free (line);
- if (fclose (fp) < 0)
- error (0, errno, "warning: cannot close %s", CVSADM_CIPROG);
- }
- else
- {
- if (! existence_error (errno))
- error (0, errno, "warning: cannot open %s", CVSADM_CIPROG);
- }
- }
-
return (err);
}
@@ -1532,9 +1512,9 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
static Dtype
commit_direntproc (callerdat, dir, repos, update_dir, entries)
void *callerdat;
- char *dir;
- char *repos;
- char *update_dir;
+ const char *dir;
+ const char *repos;
+ const char *update_dir;
List *entries;
{
Node *p;
@@ -1576,9 +1556,9 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
static int
commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
void *callerdat;
- char *dir;
+ const char *dir;
int err;
- char *update_dir;
+ const char *update_dir;
List *entries;
{
/* update the per-directory tag info */
@@ -1605,15 +1585,14 @@ findmaxrev (p, closure)
void *closure;
{
int thisrev;
- Entnode *entdata;
+ Entnode *entdata = p->data;
- entdata = (Entnode *) p->data;
if (entdata->type != ENT_FILE)
- return (0);
+ return 0;
thisrev = atoi (entdata->version);
if (thisrev > maxrev)
maxrev = thisrev;
- return (0);
+ return 0;
}
/*
@@ -1658,11 +1637,11 @@ remove_file (finfo, tag, message)
error (0, retcode == -1 ? errno : 0,
"failed to remove tag `%s' from `%s'", tag,
finfo->fullname);
- return (1);
+ return 1;
}
RCS_rewrite (finfo->rcs, NULL, NULL);
Scratch_Entry (finfo->entries, finfo->file);
- return (0);
+ return 0;
}
/* we are removing the file from either the head or a branch */
@@ -1692,12 +1671,12 @@ remove_file (finfo, tag, message)
/* no revision exists on this branch. use the previous
revision but do not lock. */
corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL);
- prev_rev = xstrdup(rev);
+ prev_rev = xstrdup (corev);
lockflag = 0;
} else
{
corev = xstrdup (rev);
- prev_rev = xstrdup(branchname);
+ prev_rev = xstrdup (branchname);
free (branchname);
}
@@ -1789,10 +1768,8 @@ finaladd (finfo, rev, tag, options)
char *options;
{
int ret;
- char *rcs;
- rcs = locate_rcs (finfo->file, finfo->repository);
- ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message);
+ ret = Checkin ('A', finfo, rev, tag, options, saved_message);
if (ret == 0)
{
char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
@@ -1803,11 +1780,10 @@ finaladd (finfo, rev, tag, options)
error (0, errno, "cannot remove %s", tmp);
free (tmp);
}
- else
- fixaddfile (finfo->file, finfo->repository);
+ else if (finfo->rcs != NULL)
+ fixaddfile (finfo->rcs->path);
(void) time (&last_register_time);
- free (rcs);
return (ret);
}
@@ -1828,19 +1804,22 @@ unlockrcs (rcs)
RCS_rewrite (rcs, NULL, NULL);
}
+
+
/*
* remove a partially added file. if we can parse it, leave it alone.
+ *
+ * FIXME: Every caller that calls this function can access finfo->rcs (the
+ * parsed RCSNode data), so we should be able to detect that the file needs
+ * to be removed without reparsing the file as we do below.
*/
static void
-fixaddfile (file, repository)
- char *file;
- char *repository;
+fixaddfile (rcs)
+ const char *rcs;
{
RCSNode *rcsfile;
- char *rcs;
int save_really_quiet;
- rcs = locate_rcs (file, repository);
save_really_quiet = really_quiet;
really_quiet = 1;
if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
@@ -1851,9 +1830,10 @@ fixaddfile (file, repository)
else
freercsnode (&rcsfile);
really_quiet = save_really_quiet;
- free (rcs);
}
+
+
/*
* put the branch back on an rcs file
*/
@@ -1877,25 +1857,46 @@ fixbranch (rcs, branch)
* do the initial part of a file add for the named file. if adding
* with a tag, put the file in the Attic and point the symbolic tag
* at the committed revision.
+ *
+ * INPUTS
+ * file The name of the file in the workspace.
+ * repository The repository directory to expect to find FILE,v in.
+ * tag The name or rev num of the branch being added to, if any.
+ * options Any RCS keyword expansion options specified by the user.
+ * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
+ * exists in the repository. If this is NULL, assume the file
+ * does not yet exist.
+ *
+ * RETURNS
+ * 0 on success.
+ * 1 on errors, after printing any appropriate error messages.
+ *
+ * ERRORS
+ * This function will return an error when any of the following functions do:
+ * add_rcs_file
+ * RCS_setattic
+ * lock_RCS
+ * RCS_checkin
+ * RCS_parse (called to verify the newly created archive file)
+ * RCS_settag
*/
static int
checkaddfile (file, repository, tag, options, rcsnode)
- char *file;
- char *repository;
- char *tag;
- char *options;
+ const char *file;
+ const char *repository;
+ const char *tag;
+ const char *options;
RCSNode **rcsnode;
{
- char *rcs;
+ RCSNode *rcs;
char *fname;
- mode_t omask;
- int retcode = 0;
- int newfile = 0;
- RCSNode *rcsfile = NULL;
- int retval;
+ int newfile = 0; /* Set to 1 if we created a new RCS archive. */
+ int retval = 1;
int adding_on_branch;
+ assert (rcsnode != NULL);
+
/* Callers expect to be able to use either "" or NULL to mean the
default keyword expansion. */
if (options != NULL && options[0] == '\0')
@@ -1907,103 +1908,49 @@ checkaddfile (file, repository, tag, options, rcsnode)
this. */
adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
- if (adding_on_branch)
- {
- rcs = xmalloc (strlen (repository) + strlen (file)
- + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
- (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
- if (! isreadable (rcs))
- {
- (void) sprintf(rcs, "%s/%s", repository, CVSATTIC);
- omask = umask (cvsumask);
- if (CVS_MKDIR (rcs, 0777) != 0 && errno != EEXIST)
- error (1, errno, "cannot make directory `%s'", rcs);;
- (void) umask (omask);
- (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file,
- RCSEXT);
- }
- }
- else
- rcs = locate_rcs (file, repository);
-
- if (isreadable (rcs))
+ if (*rcsnode == NULL)
{
- /* file has existed in the past. Prepare to resurrect. */
- char *rev;
- char *oldexpand;
+ char *rcsname;
+ char *desc = NULL;
+ size_t descalloc = 0;
+ size_t desclen = 0;
+ const char *opt;
- if ((rcsfile = *rcsnode) == NULL)
+ if ( adding_on_branch )
{
- error (0, 0, "could not find parsed rcsfile %s", file);
- retval = 1;
- goto out;
- }
-
- oldexpand = RCS_getexpand (rcsfile);
- if ((oldexpand != NULL
- && options != NULL
- && strcmp (options + 2, oldexpand) != 0)
- || (oldexpand == NULL && options != NULL))
- {
- /* We tell the user about this, because it means that the
- old revisions will no longer retrieve the way that they
- used to. */
- error (0, 0, "changing keyword expansion mode to %s", options);
- RCS_setexpand (rcsfile, options + 2);
- }
-
- if (!adding_on_branch)
- {
- /* We are adding on the trunk, so move the file out of the
- Attic. */
- if (!(rcsfile->flags & INATTIC))
- {
- error (0, 0, "warning: expected %s to be in Attic",
- rcsfile->path);
- }
-
- 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;
- goto out;
- }
+ mode_t omask;
+ rcsname = xmalloc (strlen (repository)
+ + sizeof (CVSATTIC)
+ + strlen (file)
+ + sizeof (RCSEXT)
+ + 3);
+ (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC);
+ omask = umask ( cvsumask );
+ if (CVS_MKDIR (rcsname, 0777 ) != 0 && errno != EEXIST)
+ error (1, errno, "cannot make directory `%s'", rcsname);
+ (void) umask ( omask );
+ (void) sprintf (rcsname,
+ "%s/%s/%s%s",
+ repository,
+ CVSATTIC,
+ file,
+ RCSEXT);
}
-
- rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
- /* and lock it */
- if (lock_RCS (file, rcsfile, rev, repository))
+ else
{
- error (0, 0, "cannot lock `%s'.", rcs);
- if (rev != NULL)
- free (rev);
- retval = 1;
- goto out;
+ rcsname = xmalloc (strlen (repository)
+ + strlen (file)
+ + sizeof (RCSEXT)
+ + 2);
+ (void) sprintf (rcsname,
+ "%s/%s%s",
+ repository,
+ file,
+ RCSEXT);
}
- if (rev != NULL)
- free (rev);
- }
- else
- {
/* this is the first time we have ever seen this file; create
- an rcs file. */
-
- char *desc;
- size_t descalloc;
- size_t desclen;
-
- char *opt;
-
- desc = NULL;
- descalloc = 0;
- desclen = 0;
+ an RCS file. */
fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ sizeof (CVSEXT_LOG) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
@@ -2037,25 +1984,79 @@ checkaddfile (file, repository, tag, options, rcsnode)
RCS_checkin indicate that this is a new file? Or does the
"RCS file" message serve some function?). */
cvs_output ("RCS file: ", 0);
- cvs_output (rcs, 0);
+ cvs_output (rcsname, 0);
cvs_output ("\ndone\n", 0);
- if (add_rcs_file (NULL, rcs, file, NULL, opt,
+ if (add_rcs_file (NULL, rcsname, file, NULL, opt,
NULL, NULL, 0, NULL,
desc, desclen, NULL) != 0)
{
- retval = 1;
+ if (rcsname != NULL)
+ free (rcsname);
goto out;
}
- rcsfile = RCS_parsercsfile (rcs);
+ rcs = RCS_parsercsfile (rcsname);
newfile = 1;
+ if (rcsname != NULL)
+ free (rcsname);
if (desc != NULL)
free (desc);
- if (rcsnode != NULL)
+ *rcsnode = rcs;
+ }
+ else
+ {
+ /* file has existed in the past. Prepare to resurrect. */
+ char *rev;
+ char *oldexpand;
+
+ rcs = *rcsnode;
+
+ oldexpand = RCS_getexpand (rcs);
+ if ((oldexpand != NULL
+ && options != NULL
+ && strcmp (options + 2, oldexpand) != 0)
+ || (oldexpand == NULL && options != NULL))
+ {
+ /* We tell the user about this, because it means that the
+ old revisions will no longer retrieve the way that they
+ used to. */
+ error (0, 0, "changing keyword expansion mode to %s", options);
+ RCS_setexpand (rcs, options + 2);
+ }
+
+ if (!adding_on_branch)
{
- assert (*rcsnode == NULL);
- *rcsnode = rcsfile;
+ /* We are adding on the trunk, so move the file out of the
+ Attic. */
+ if (!(rcs->flags & INATTIC))
+ {
+ error (0, 0, "warning: expected %s to be in Attic",
+ rcs->path);
+ }
+
+ /* 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 (rcs, 0))
+ {
+ goto out;
+ }
}
+
+ rev = RCS_getversion (rcs, tag, NULL, 1, (int *) NULL);
+ /* and lock it */
+ if (lock_RCS (file, rcs, rev, repository))
+ {
+ error (0, 0, "cannot lock `%s'.", rcs->path);
+ if (rev != NULL)
+ free (rev);
+ goto out;
+ }
+
+ if (rev != NULL)
+ free (rev);
}
/* when adding a file for the first time, and using a tag, we need
@@ -2066,6 +2067,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
char *tmp;
FILE *fp;
+ int retcode;
/* move the new file out of the way. */
fname = xmalloc (strlen (file) + sizeof (CVSADM)
@@ -2085,14 +2087,13 @@ checkaddfile (file, repository, tag, options, rcsnode)
/* commit a dead revision. */
(void) sprintf (tmp, "file %s was initially added on branch %s.",
file, tag);
- retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
+ retcode = RCS_checkin (rcs, 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;
+ "could not create initial dead revision %s", rcs->path);
goto out;
}
@@ -2101,58 +2102,39 @@ checkaddfile (file, repository, tag, options, rcsnode)
free (fname);
/* double-check that the file was written correctly */
- freercsnode (&rcsfile);
- rcsfile = RCS_parse (file, repository);
- if (rcsfile == NULL)
+ freercsnode (&rcs);
+ rcs = RCS_parse (file, repository);
+ if (rcs == NULL)
{
- error (0, 0, "could not read %s", rcs);
- retval = 1;
+ error (0, 0, "could not read %s", rcs->path);
goto out;
}
- if (rcsnode != NULL)
- *rcsnode = rcsfile;
+ *rcsnode = rcs;
/* and lock it once again. */
- if (lock_RCS (file, rcsfile, NULL, repository))
+ if (lock_RCS (file, rcs, NULL, repository))
{
- error (0, 0, "cannot lock `%s'.", rcs);
- retval = 1;
+ error (0, 0, "cannot lock `%s'.", rcs->path);
goto out;
}
}
/* when adding with a tag, we need to stub a branch, if it
doesn't already exist. */
-
- if (rcsfile == NULL)
- {
- if (rcsnode != NULL && *rcsnode != NULL)
- rcsfile = *rcsnode;
- else
- {
- rcsfile = RCS_parse (file, repository);
- if (rcsfile == NULL)
- {
- error (0, 0, "could not read %s", rcs);
- retval = 1;
- goto out;
- }
- }
- }
-
- if (!RCS_nodeisbranch (rcsfile, tag))
+ if (!RCS_nodeisbranch (rcs, tag))
{
/* branch does not exist. Stub it. */
char *head;
char *magicrev;
+ int retcode;
- fixbranch(rcsfile, sbranch);
+ fixbranch (rcs, sbranch);
- head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
- magicrev = RCS_magicrev (rcsfile, head);
+ head = RCS_getversion (rcs, NULL, NULL, 0, (int *) NULL);
+ magicrev = RCS_magicrev (rcs, head);
- retcode = RCS_settag (rcsfile, tag, magicrev);
- RCS_rewrite (rcsfile, NULL, NULL);
+ retcode = RCS_settag (rcs, tag, magicrev);
+ RCS_rewrite (rcs, NULL, NULL);
free (head);
free (magicrev);
@@ -2160,26 +2142,24 @@ checkaddfile (file, repository, tag, options, rcsnode)
if (retcode != 0)
{
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
- "could not stub branch %s for %s", tag, rcs);
- retval = 1;
+ "could not stub branch %s for %s", tag, rcs->path);
goto out;
}
}
else
{
/* lock the branch. (stubbed branches need not be locked.) */
- if (lock_RCS (file, rcsfile, NULL, repository))
+ if (lock_RCS (file, rcs, NULL, repository))
{
- error (0, 0, "cannot lock `%s'.", rcs);
- retval = 1;
+ error (0, 0, "cannot lock `%s'.", rcs->path);
goto out;
}
}
- if (rcsnode && *rcsnode != rcsfile)
+ if (*rcsnode != rcs)
{
freercsnode(rcsnode);
- *rcsnode = rcsfile;
+ *rcsnode = rcs;
}
}
@@ -2207,7 +2187,6 @@ checkaddfile (file, repository, tag, options, rcsnode)
out:
if (retval != 0 && SIG_inCrSect ())
SIG_endCrSect ();
- free (rcs);
return retval;
}
@@ -2219,10 +2198,10 @@ checkaddfile (file, repository, tag, options, rcsnode)
*/
static int
lock_RCS (user, rcs, rev, repository)
- char *user;
+ const char *user;
RCSNode *rcs;
- char *rev;
- char *repository;
+ const char *rev;
+ const char *repository;
{
char *branch = NULL;
int err = 0;
@@ -2251,11 +2230,11 @@ lock_RCS (user, rcs, rev, repository)
return (1);
}
}
- err = RCS_lock(rcs, NULL, 1);
+ err = RCS_lock (rcs, NULL, 1);
}
else
{
- (void) RCS_lock(rcs, rev, 1);
+ RCS_lock (rcs, rev, 1);
}
/* We used to call RCS_rewrite here, and that might seem
@@ -2301,9 +2280,8 @@ void
update_delproc (p)
Node *p;
{
- struct logfile_info *li;
+ struct logfile_info *li = p->data;
- li = (struct logfile_info *) p->data;
if (li->tag)
free (li->tag);
if (li->rev_old)
@@ -2320,9 +2298,8 @@ static void
ci_delproc (p)
Node *p;
{
- struct commit_info *ci;
+ struct commit_info *ci = p->data;
- ci = (struct commit_info *) p->data;
if (ci->rev)
free (ci->rev);
if (ci->tag)
@@ -2339,37 +2316,9 @@ static void
masterlist_delproc (p)
Node *p;
{
- struct master_lists *ml;
+ struct master_lists *ml = p->data;
- ml = (struct master_lists *) p->data;
dellist (&ml->ulist);
dellist (&ml->cilist);
free (ml);
}
-
-/* Find an RCS file in the repository. Most parts of CVS will want to
- rely instead on RCS_parse which performs a similar operation and is
- called by recurse.c which then puts the result in useful places
- like the rcs field of struct file_info.
-
- REPOSITORY is the repository (including the directory) and FILE is
- the filename within that directory (without RCSEXT). Returns a
- newly-malloc'd array containing the absolute pathname of the RCS
- file that was found. */
-static char *
-locate_rcs (file, repository)
- char *file;
- char *repository;
-{
- char *rcs;
-
- rcs = xmalloc (strlen (repository) + strlen (file) + sizeof (RCSEXT) + 10);
- (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
- if (!isreadable (rcs))
- {
- (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
- if (!isreadable (rcs))
- (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
- }
- return rcs;
-}
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index ed49ae3..68d46cc 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -85,6 +85,7 @@ extern int errno;
#include "system.h"
#include "hash.h"
+#include "stack.h"
#include "root.h"
@@ -128,8 +129,6 @@ extern int errno;
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository."
#define CVSADM_ROOT "CVS/Root."
-#define CVSADM_CIPROG "CVS/Checkin.prog"
-#define CVSADM_UPROG "CVS/Update.prog"
#define CVSADM_TAG "CVS/Tag."
#define CVSADM_NOTIFY "CVS/Notify."
#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
@@ -145,8 +144,6 @@ extern int errno;
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository"
#define CVSADM_ROOT "CVS/Root"
-#define CVSADM_CIPROG "CVS/Checkin.prog"
-#define CVSADM_UPROG "CVS/Update.prog"
#define CVSADM_TAG "CVS/Tag"
#define CVSADM_NOTIFY "CVS/Notify"
#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
@@ -367,7 +364,7 @@ typedef enum direnter_type Dtype;
#define CVS_LOCK_READ 1
#define CVS_LOCK_WRITE 2
-extern char *program_name, *program_path, *command_name;
+extern const char *program_name, *program_path, *cvs_cmd_name;
extern char *Tmpdir, *Editor;
extern int cvsadmin_root;
extern char *CurDir;
@@ -416,7 +413,8 @@ extern char hostname[];
/* Externs that are included directly in the CVS sources */
-int RCS_merge PROTO((RCSNode *, char *, char *, char *, char *, char *));
+int RCS_merge PROTO((RCSNode *, const char *, const char *, const char *,
+ const char *, const char *));
/* Flags used by RCS_* functions. See the description of the individual
functions for which flags mean what for each function. */
#define RCS_FLAGS_FORCE 1
@@ -426,14 +424,14 @@ int RCS_merge PROTO((RCSNode *, char *, char *, char *, char *, char *));
#define RCS_FLAGS_KEEPFILE 16
extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile,
- char *opts, char *options,
- char *rev1, char *rev2,
- char *label1, char *label2,
- char *workfile));
-extern int diff_exec PROTO ((char *file1, char *file2,
- char *label1, char *label2,
- char *options, char *out));
-
+ const char *opts, const char *options,
+ const char *rev1, const char *rev1_cache,
+ const char *rev2, const char *label1,
+ const char *label2, const char *workfile));
+extern int diff_exec PROTO ((const char *file1, const char *file2,
+ const char *label1, const char *label2,
+ const char *options, const char *out));
+
#include "error.h"
@@ -452,34 +450,36 @@ void date_to_internet PROTO ((char *, const char *));
void date_to_tm PROTO ((struct tm *, const char *));
void tm_to_internet PROTO ((char *, const struct tm *));
-char *Name_Repository PROTO((char *dir, char *update_dir));
-char *Short_Repository PROTO((char *repository));
+char *Name_Repository PROTO((const char *dir, const char *update_dir));
+const char *Short_Repository PROTO((const char *repository));
void Sanitize_Repository_Name PROTO((char *repository));
char *Name_Root PROTO((char *dir, char *update_dir));
void free_cvsroot_t PROTO((cvsroot_t *root_in));
-cvsroot_t *parse_cvsroot PROTO((char *root));
-cvsroot_t *local_cvsroot PROTO((char *dir));
-void Create_Root PROTO((char *dir, char *rootdir));
+cvsroot_t *parse_cvsroot PROTO((const char *root));
+cvsroot_t *local_cvsroot PROTO((const char *dir));
+void Create_Root PROTO((const char *dir, const char *rootdir));
void root_allow_add PROTO ((char *));
void root_allow_free PROTO ((void));
int root_allow_ok PROTO ((char *));
-char *gca PROTO((const char *rev1, const char *rev2));
+char *previous_rev PROTO ((RCSNode *rcs, const char *rev));
+char *gca PROTO ((const char *rev1, const char *rev2));
extern void check_numeric PROTO ((const char *, int, char **));
-char *getcaller PROTO((void));
-char *time_stamp PROTO((char *file));
+char *getcaller PROTO ((void));
+char *time_stamp PROTO ((const char *file));
void *xmalloc PROTO((size_t bytes));
void *xrealloc PROTO((void *ptr, size_t bytes));
void expand_string PROTO ((char **, size_t *, size_t));
void xrealloc_and_strcat PROTO ((char **, size_t *, const char *));
char *xstrdup PROTO((const char *str));
-void strip_trailing_newlines PROTO((char *str));
-int pathname_levels PROTO ((char *path));
+int strip_trailing_newlines PROTO((char *str));
+int pathname_levels PROTO ((const char *path));
-typedef int (*CALLPROC) PROTO((char *repository, char *value));
-int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all));
+typedef int (*CALLPROC) PROTO((const char *repository, const char *value));
+int Parse_Info PROTO((const char *infofile, const char *repository,
+ CALLPROC callproc, int all));
extern int parse_config PROTO ((char *));
typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(());
@@ -492,8 +492,11 @@ int isreadable PROTO((const char *file));
int iswritable PROTO((const char *file));
int isaccessible PROTO((const char *file, const int mode));
int isabsolute PROTO((const char *filename));
+#ifdef HAVE_READLINK
char *xreadlink PROTO((const char *link));
-char *last_component PROTO((char *path));
+#endif
+char *xresolvepath PROTO((const char *path));
+const char *last_component PROTO((const char *path));
char *get_homedir PROTO ((void));
char *strcat_filename_onto_homedir PROTO ((const char *, const char *));
char *cvs_temp_name PROTO ((void));
@@ -505,16 +508,57 @@ char *increment_revnum PROTO ((const char *));
int compare_revnums PROTO ((const char *, const char *));
int unlink_file PROTO((const char *f));
int unlink_file_dir PROTO((const char *f));
+
+
+
+/* This is the structure that the recursion processor passes to the
+ fileproc to tell it about a particular file. */
+struct file_info
+{
+ /* Name of the file, without any directory component. */
+ const char *file;
+
+ /* Name of the directory we are in, relative to the directory in
+ which this command was issued. We have cd'd to this directory
+ (either in the working directory or in the repository, depending
+ on which sort of recursion we are doing). If we are in the directory
+ in which the command was issued, this is "". */
+ const char *update_dir;
+
+ /* update_dir and file put together, with a slash between them as
+ necessary. This is the proper way to refer to the file in user
+ messages. */
+ const char *fullname;
+
+ /* Name of the directory corresponding to the repository which contains
+ this file. */
+ const char *repository;
+
+ /* The pre-parsed entries for this directory. */
+ List *entries;
+
+ RCSNode *rcs;
+};
+
+
+
int update PROTO((int argc, char *argv[]));
+/* The only place this is currently used outside of update.c is add.c.
+ * Restricting its use to update.c seems to be in the best interest of
+ * modularity, but I can't think of a good way to get an update of a
+ * resurrected file done and print the fact otherwise.
+ */
+void write_letter PROTO ((struct file_info *finfo, int letter));
int xcmp PROTO((const char *file1, const char *file2));
int yesno PROTO((void));
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 dotemplate));
-extern int expand_at_signs PROTO ((char *, off_t, FILE *));
-
+extern int Create_Admin PROTO ((const char *dir, const char *update_dir,
+ const char *repository, const char *tag,
+ const char *date,
+ int nonbranch, int warn, int dotemplate));
+extern int expand_at_signs PROTO ((const char *, off_t, FILE *));
+
/* Locking subsystem (implemented in lock.c). */
int Reader_Lock PROTO((char *xrepository));
@@ -530,11 +574,12 @@ extern void lock_dir_for_write PROTO ((char *));
/* LockDir setting from CVSROOT/config. */
extern char *lock_dir;
-
-void Scratch_Entry PROTO((List * list, char *fname));
+
+void Scratch_Entry PROTO((List * list, const char *fname));
void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
-void WriteTag PROTO ((char *dir, char *tag, char *date, int nonbranch,
- char *update_dir, char *repository));
+void WriteTag PROTO ((const char *dir, const char *tag, const char *date,
+ int nonbranch, const char *update_dir,
+ const char *repository));
void WriteTemplate PROTO ((char *dir, char *update_dir));
void cat_module PROTO((int status));
void check_entries PROTO((char *dir));
@@ -548,18 +593,17 @@ void ign_add PROTO((char *ign, int hold));
void ign_add_file PROTO((char *file, int hold));
void ign_setup PROTO((void));
void ign_dir_add PROTO((char *name));
-int ignore_directory PROTO((char *name));
-typedef void (*Ignore_proc) PROTO ((char *, char *));
-extern void ignore_files PROTO ((List *, List *, char *, Ignore_proc));
+int ignore_directory PROTO((const char *name));
+typedef void (*Ignore_proc) PROTO ((const char *, const char *));
+extern void ignore_files PROTO ((List *, List *, const char *, Ignore_proc));
extern int ign_inhibit_server;
-extern int ign_case;
#include "update.h"
void line2argv PROTO ((int *pargc, char ***argv, char *line, char *sepchars));
void make_directories PROTO((const char *name));
void make_directory PROTO((const char *name));
-extern int mkdir_if_needed PROTO ((char *name));
+extern int mkdir_if_needed PROTO ((const char *name));
void rename_file PROTO((const char *from, const char *to));
/* 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
@@ -572,68 +616,41 @@ extern void expand_wild PROTO ((int argc, char **argv,
int *pargc, char ***pargv));
#ifdef SERVER_SUPPORT
-extern int cvs_casecmp PROTO ((char *, char *));
+extern int cvs_casecmp PROTO ((const char *, const char *));
extern int fopen_case PROTO ((char *, char *, FILE **, char **));
#endif
void strip_trailing_slashes PROTO((char *path));
void update_delproc PROTO((Node * p));
void usage PROTO((const char *const *cpp));
-void xchmod PROTO((char *fname, int writable));
+void xchmod PROTO((const char *fname, int writable));
char *xgetwd PROTO((void));
List *Find_Names PROTO((char *repository, int which, int aflag,
- List ** optentries));
-void Register PROTO((List * list, char *fname, char *vn, char *ts,
- char *options, char *tag, char *date, char *ts_conflict));
-void Update_Logfile PROTO((char *repository, char *xmessage, FILE * xlogfp,
- List * xchanges));
-void do_editor PROTO((char *dir, char **messagep,
- char *repository, List * changes));
+ List **optentries));
+void Register PROTO((List * list, const char *fname, const char *vn,
+ const char *ts, const char *options, const char *tag,
+ const char *date, const char *ts_conflict));
+void Update_Logfile PROTO((const char *repository, const char *xmessage,
+ FILE * xlogfp, List * xchanges));
+void do_editor PROTO((const char *dir, char **messagep,
+ const char *repository, List * changes));
-void do_verify PROTO((char **messagep, char *repository));
+void do_verify PROTO((char **messagep, const char *repository));
typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten, int local_specified,
char *omodule, char *msg));
-/* This is the structure that the recursion processor passes to the
- fileproc to tell it about a particular file. */
-struct file_info
-{
- /* Name of the file, without any directory component. */
- char *file;
-
- /* Name of the directory we are in, relative to the directory in
- which this command was issued. We have cd'd to this directory
- (either in the working directory or in the repository, depending
- on which sort of recursion we are doing). If we are in the directory
- in which the command was issued, this is "". */
- char *update_dir;
-
- /* update_dir and file put together, with a slash between them as
- necessary. This is the proper way to refer to the file in user
- messages. */
- char *fullname;
-
- /* Name of the directory corresponding to the repository which contains
- this file. */
- char *repository;
-
- /* The pre-parsed entries for this directory. */
- List *entries;
-
- RCSNode *rcs;
-};
-
typedef int (*FILEPROC) PROTO ((void *callerdat, struct file_info *finfo));
typedef int (*FILESDONEPROC) PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
-typedef Dtype (*DIRENTPROC) PROTO ((void *callerdat, char *dir,
- char *repos, char *update_dir,
+ const char *repository,
+ const char *update_dir,
+ List *entries));
+typedef Dtype (*DIRENTPROC) PROTO ((void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
List *entries));
-typedef int (*DIRLEAVEPROC) PROTO ((void *callerdat, char *dir, int err,
- char *update_dir, List *entries));
+typedef int (*DIRLEAVEPROC) PROTO ((void *callerdat, const char *dir, int err,
+ const char *update_dir, List *entries));
extern int mkmodules PROTO ((char *dir));
extern int init PROTO ((int argc, char **argv));
@@ -642,20 +659,22 @@ int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg,
CALLBACKPROC callback_proc, char *where, int shorten,
int local_specified, int run_module_prog, int build_dirs,
char *extra_arg));
-void history_write PROTO((int type, char *update_dir, char *revs, char *name,
- char *repository));
+void history_write PROTO((int type, const char *update_dir, const char *revs,
+ const char *name, const char *repository));
int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc,
DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
void *callerdat,
int argc, char *argv[], int local, int which,
int aflag, int locktype, char *update_preload,
- int dosrcs));
+ int dosrcs, char *repository));
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));
+void read_cvsrc PROTO((int *argc, char ***argv, const char *cmdname));
-char *make_message_rcslegal PROTO((char *message));
+char *make_message_rcslegal PROTO((const char *message));
+extern int file_has_conflict PROTO ((const struct file_info *,
+ const char *ts_conflict));
extern int file_has_markers PROTO ((const struct file_info *));
extern void get_file PROTO ((const char *, const char *, const char *,
char **, size_t *, size_t *));
@@ -665,13 +684,13 @@ extern void resolve_symlink PROTO ((char **filename));
void sleep_past PROTO ((time_t desttime));
/* flags for run_exec(), the fast system() for CVS */
-#define RUN_NORMAL 0x0000 /* no special behaviour */
-#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */
-#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */
-#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
-#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
-#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
-#define RUN_TTY (char *)0 /* for the benefit of lint */
+#define RUN_NORMAL 0x0000 /* no special behaviour */
+#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */
+#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */
+#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
+#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
+#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
+#define RUN_TTY (char *)0 /* for the benefit of lint */
void run_arg PROTO((const char *s));
void run_print PROTO((FILE * fp));
@@ -681,7 +700,7 @@ int run_exec PROTO((const char *stin, const char *stout, const char *sterr,
/* other similar-minded stuff from run.c. */
FILE *run_popen PROTO((const char *, const char *));
-int piped_child PROTO((char **, int *, int *));
+int piped_child PROTO((const char **, int *, int *));
void close_on_exec PROTO((int));
pid_t waitpid PROTO((pid_t, int *, int));
@@ -764,7 +783,7 @@ void freevers_ts PROTO ((Vers_TS ** versp));
/* Miscellaneous CVS infrastructure which layers on top of the recursion
processor (for example, needs struct file_info). */
-int Checkin PROTO ((int type, struct file_info *finfo, char *rcs, char *rev,
+int Checkin PROTO ((int type, struct file_info *finfo, char *rev,
char *tag, char *options, char *message));
int No_Difference PROTO ((struct file_info *finfo, Vers_TS *vers));
/* TODO: can the finfo argument to special_file_mismatch be changed? -twp */
@@ -838,15 +857,15 @@ void wrap_send PROTO ((void));
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
void wrap_unparse_rcs_options PROTO ((char **, int));
#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
-
+
/* Pathname expansion */
-char *expand_path PROTO((char *name, char *file, int line));
+char *expand_path PROTO((const char *name, const char *file, int line));
/* User variables. */
extern List *variable_list;
extern void variable_set PROTO ((char *nameval));
-
+
int watch PROTO ((int argc, char **argv));
int edit PROTO ((int argc, char **argv));
int unedit PROTO ((int argc, char **argv));
@@ -907,4 +926,4 @@ extern void cvs_output_binary PROTO ((char *, size_t));
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 *));
+extern void cvs_output_tagged PROTO ((const char *, const char *));
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c
index b29bc8f..ec21599 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -16,6 +16,7 @@
* $FreeBSD$
*/
+#include <assert.h>
#include "cvs.h"
enum diff_file
@@ -27,18 +28,21 @@ enum diff_file
DIFF_SAME
};
-static Dtype diff_dirproc PROTO ((void *callerdat, char *dir,
- char *pos_repos, char *update_dir,
- List *entries));
+static Dtype diff_dirproc PROTO ((void *callerdat, const char *dir,
+ const char *pos_repos,
+ const char *update_dir,
+ List *entries));
static int diff_filesdoneproc PROTO ((void *callerdat, int err,
- char *repos, char *update_dir,
- List *entries));
-static int diff_dirleaveproc PROTO ((void *callerdat, char *dir,
- int err, char *update_dir,
- List *entries));
-static enum diff_file diff_file_nodiff PROTO ((struct file_info *finfo,
+ const char *repos,
+ const char *update_dir,
+ List *entries));
+static int diff_dirleaveproc PROTO ((void *callerdat, const char *dir,
+ int err, const char *update_dir,
+ List *entries));
+static enum diff_file diff_file_nodiff PROTO(( struct file_info *finfo,
Vers_TS *vers,
- enum diff_file));
+ enum diff_file,
+ char **rev1_cache ));
static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static void diff_mark_errors PROTO((int err));
@@ -275,6 +279,13 @@ diff (argc, argv)
diff_join2 = NULL;
optind = 0;
+ /* FIXME: This should really be allocating an argv to be passed to diff
+ * later rather than strcatting onto the opts variable. We have some
+ * handling routines that can already handle most of the argc/argv
+ * maintenance for us and currently, if anyone were to attempt to pass a
+ * quoted string in here, it would be split on spaces and tabs on its way
+ * to diff.
+ */
while ((c = getopt_long (argc, argv,
"+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:j:",
longopts, &option_index)) != -1)
@@ -450,7 +461,8 @@ diff (argc, argv)
/* start the recursion processor */
err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
diff_dirleaveproc, NULL, argc, argv, local,
- which, 0, CVS_LOCK_READ, (char *) NULL, 1);
+ which, 0, CVS_LOCK_READ, (char *) NULL, 1
+ (char *) NULL);
}
/* clean up */
@@ -481,16 +493,12 @@ diff_fileproc (callerdat, finfo)
int status, err = 2; /* 2 == trouble, like rcsdiff */
Vers_TS *vers;
enum diff_file empty_file = DIFF_DIFFERENT;
- char *tmp;
- char *tocvsPath;
- char *fname;
+ char *tmp = NULL;
+ char *tocvsPath = NULL;
+ char *fname = NULL;
char *label1;
char *label2;
-
- /* Initialize these solely to avoid warnings from gcc -Wall about
- variables that might be used uninitialized. */
- tmp = NULL;
- fname = NULL;
+ char *rev1_cache = NULL;
user_file_rev = 0;
vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
@@ -538,30 +546,69 @@ diff_fileproc (callerdat, finfo)
error (0, 0,
"%s no longer exists, no comparison available",
finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ goto out;
}
}
else
{
error (0, 0, "I know nothing about %s", finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ goto out;
}
}
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
{
- if (empty_files)
- empty_file = DIFF_ADDED;
- else
+ /* The file was added locally. */
+ int exists = 0;
+
+ if (vers->srcfile != NULL)
{
- error (0, 0, "%s is a new entry, no comparison available",
- finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ /* The file does exist in the repository. */
+
+ if ((diff_rev1 != NULL || diff_date1 != NULL))
+ {
+ /* special handling for TAG_HEAD */
+ if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+ {
+ char *head =
+ (vers->vn_rcs == NULL
+ ? NULL
+ : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ exists = head != NULL && !RCS_isdead(vers->srcfile, head);
+ if (head != NULL)
+ free (head);
+ }
+ else
+ {
+ Vers_TS *xvers;
+
+ xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
+ 1, 0);
+ exists = xvers->vn_rcs != NULL
+ && !RCS_isdead (xvers->srcfile, xvers->vn_rcs);
+ freevers_ts (&xvers);
+ }
+ }
+ else
+ {
+ /* The file was added locally, but an RCS archive exists. Our
+ * base revision must be dead.
+ */
+ /* No need to set, exists = 0, here. That's the default. */
+ }
+ }
+ if (!exists)
+ {
+ /* If we got here, then either the RCS archive does not exist or
+ * the relevant revision is dead.
+ */
+ if (empty_files)
+ empty_file = DIFF_ADDED;
+ else
+ {
+ error (0, 0, "%s is a new entry, no comparison available",
+ finfo->fullname);
+ goto out;
+ }
}
}
else if (vers->vn_user[0] == '-')
@@ -572,9 +619,7 @@ diff_fileproc (callerdat, finfo)
{
error (0, 0, "%s was removed, no comparison available",
finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ goto out;
}
}
else
@@ -583,18 +628,14 @@ diff_fileproc (callerdat, finfo)
{
error (0, 0, "cannot find revision control file for %s",
finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ goto out;
}
else
{
if (vers->ts_user == NULL)
{
error (0, 0, "cannot find %s", finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
+ goto out;
}
else if (!strcmp (vers->ts_user, vers->ts_rcs))
{
@@ -606,73 +647,21 @@ diff_fileproc (callerdat, finfo)
}
}
- empty_file = diff_file_nodiff (finfo, vers, empty_file);
- if (empty_file == DIFF_SAME || empty_file == DIFF_ERROR)
- {
- freevers_ts (&vers);
- if (empty_file == DIFF_SAME)
- {
- /* In the server case, would be nice to send a "Checked-in"
- response, so that the client can rewrite its timestamp.
- server_checked_in by itself isn't the right thing (it
- needs a server_register), but I'm not sure what is.
- It isn't clear to me how "cvs status" handles this (that
- is, for a client which sends Modified not Is-modified to
- "cvs status"), but it does. */
- return (0);
- }
- else
- {
- diff_mark_errors (err);
- return (err);
- }
- }
-
- if (empty_file == DIFF_DIFFERENT)
+ empty_file = diff_file_nodiff( finfo, vers, empty_file, &rev1_cache );
+ if( empty_file == DIFF_SAME )
{
- int dead1, dead2;
-
- if (use_rev1 == NULL)
- dead1 = 0;
- else
- dead1 = RCS_isdead (vers->srcfile, use_rev1);
- if (use_rev2 == NULL)
- dead2 = 0;
- else
- dead2 = RCS_isdead (vers->srcfile, use_rev2);
-
- if (dead1 && dead2)
- {
- freevers_ts (&vers);
- return (0);
- }
- else if (dead1)
- {
- if (empty_files)
- empty_file = DIFF_ADDED;
- else
- {
- error (0, 0, "%s is a new entry, no comparison available",
- finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
- }
- }
- else if (dead2)
- {
- if (empty_files)
- empty_file = DIFF_REMOVED;
- else
- {
- error (0, 0, "%s was removed, no comparison available",
- finfo->fullname);
- freevers_ts (&vers);
- diff_mark_errors (err);
- return (err);
- }
- }
+ /* In the server case, would be nice to send a "Checked-in"
+ response, so that the client can rewrite its timestamp.
+ server_checked_in by itself isn't the right thing (it
+ needs a server_register), but I'm not sure what is.
+ It isn't clear to me how "cvs status" handles this (that
+ is, for a client which sends Modified not Is-modified to
+ "cvs status"), but it does. */
+ err = 0;
+ goto out;
}
+ else if( empty_file == DIFF_ERROR )
+ goto out;
/* Output an "Index:" line for patch to use */
cvs_output ("Index: ", 0);
@@ -680,7 +669,7 @@ diff_fileproc (callerdat, finfo)
cvs_output ("\n", 1);
tocvsPath = wrap_tocvs_process_file(finfo->file);
- if (tocvsPath)
+ if( tocvsPath != NULL )
{
/* Backup the current version of the file to CVS/,,filename */
fname = xmalloc (strlen (finfo->file)
@@ -709,7 +698,8 @@ diff_fileproc (callerdat, finfo)
make_file_label (DEVNULL, NULL, NULL);
else
label1 =
- make_file_label (finfo->fullname, use_rev1, vers ? vers->srcfile : NULL);
+ make_file_label (finfo->fullname, use_rev1,
+ vers ? vers->srcfile : NULL);
}
if (!have_rev2_label)
@@ -719,7 +709,8 @@ diff_fileproc (callerdat, finfo)
make_file_label (DEVNULL, NULL, NULL);
else
label2 =
- make_file_label (finfo->fullname, use_rev2, vers ? vers->srcfile : NULL);
+ make_file_label (finfo->fullname, use_rev2,
+ vers ? vers->srcfile : NULL);
}
if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
@@ -742,7 +733,8 @@ RCS file: ", 0);
if (empty_file == DIFF_ADDED)
{
if (use_rev2 == NULL)
- status = diff_exec (DEVNULL, finfo->file, label1, label2, opts, RUN_TTY);
+ status = diff_exec (DEVNULL, finfo->file, label1, label2, opts,
+ RUN_TTY);
else
{
int retcode;
@@ -755,11 +747,8 @@ RCS file: ", 0);
: vers->options),
tmp, (RCSCHECKOUTPROC) NULL,
(void *) NULL);
- if (retcode != 0)
- {
- diff_mark_errors (err);
- return err;
- }
+ if( retcode != 0 )
+ goto out;
status = diff_exec (DEVNULL, tmp, label1, label2, opts, RUN_TTY);
}
@@ -775,26 +764,24 @@ RCS file: ", 0);
tmp, (RCSCHECKOUTPROC) NULL,
(void *) NULL);
if (retcode != 0)
- {
- diff_mark_errors (err);
- return err;
- }
+ goto out;
status = diff_exec (tmp, DEVNULL, label1, label2, opts, RUN_TTY);
}
}
else
{
- status = RCS_exec_rcsdiff (vers->srcfile, opts,
- *options ? options : vers->options,
- use_rev1, use_rev2,
- label1, label2,
- finfo->file);
-
- if (label1) free (label1);
- if (label2) free (label2);
+ status = RCS_exec_rcsdiff(vers->srcfile, opts,
+ *options ? options : vers->options,
+ use_rev1, rev1_cache, use_rev2,
+ label1, label2,
+ finfo->file);
+
}
+ if (label1) free (label1);
+ if (label2) free (label2);
+
switch (status)
{
case -1: /* fork failed */
@@ -808,7 +795,8 @@ RCS file: ", 0);
break;
}
- if (tocvsPath)
+out:
+ if( tocvsPath != NULL )
{
if (unlink_file_dir (finfo->file) < 0)
if (! existence_error (errno))
@@ -820,17 +808,25 @@ RCS file: ", 0);
free (fname);
}
- if (empty_file == DIFF_REMOVED
- || (empty_file == DIFF_ADDED && use_rev2 != NULL))
+ /* Call CVS_UNLINK() rather than unlink_file() below to avoid the check
+ * for noexec.
+ */
+ if( tmp != NULL )
{
- if (CVS_UNLINK (tmp) < 0)
+ if (CVS_UNLINK(tmp) < 0)
error (0, errno, "cannot remove %s", tmp);
free (tmp);
}
+ if( rev1_cache != NULL )
+ {
+ if( CVS_UNLINK( rev1_cache ) < 0 )
+ error( 0, errno, "cannot remove %s", rev1_cache );
+ free( rev1_cache );
+ }
freevers_ts (&vers);
diff_mark_errors (err);
- return (err);
+ return err;
}
/*
@@ -853,9 +849,9 @@ diff_mark_errors (err)
static Dtype
diff_dirproc (callerdat, dir, pos_repos, update_dir, entries)
void *callerdat;
- char *dir;
- char *pos_repos;
- char *update_dir;
+ const char *dir;
+ const char *pos_repos;
+ const char *update_dir;
List *entries;
{
/* XXX - check for dirs we don't want to process??? */
@@ -877,8 +873,8 @@ static int
diff_filesdoneproc (callerdat, err, repos, update_dir, entries)
void *callerdat;
int err;
- char *repos;
- char *update_dir;
+ const char *repos;
+ const char *update_dir;
List *entries;
{
return (diff_errors);
@@ -891,9 +887,9 @@ diff_filesdoneproc (callerdat, err, repos, update_dir, entries)
static int
diff_dirleaveproc (callerdat, dir, err, update_dir, entries)
void *callerdat;
- char *dir;
+ const char *dir;
int err;
- char *update_dir;
+ const char *update_dir;
List *entries;
{
return (diff_errors);
@@ -903,10 +899,13 @@ diff_dirleaveproc (callerdat, dir, err, update_dir, entries)
* verify that a file is different
*/
static enum diff_file
-diff_file_nodiff (finfo, vers, empty_file)
+diff_file_nodiff( finfo, vers, empty_file, rev1_cache )
struct file_info *finfo;
Vers_TS *vers;
enum diff_file empty_file;
+ char **rev1_cache; /* Cache the content of rev1 if we have to look
+ * it up.
+ */
{
Vers_TS *xvers;
int retcode;
@@ -922,9 +921,10 @@ diff_file_nodiff (finfo, vers, empty_file)
{
/* special handling for TAG_HEAD XXX */
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
- use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
- ? NULL
- : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ {
+ if (vers->vn_rcs != NULL && vers->srcfile != NULL)
+ use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+ }
else
{
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
@@ -937,9 +937,10 @@ diff_file_nodiff (finfo, vers, empty_file)
{
/* special handling for TAG_HEAD XXX */
if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
- use_rev2 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
- ? NULL
- : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ {
+ if (vers->vn_rcs != NULL && vers->srcfile != NULL)
+ use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+ }
else
{
xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
@@ -948,19 +949,39 @@ diff_file_nodiff (finfo, vers, empty_file)
freevers_ts (&xvers);
}
- if (use_rev1 == NULL)
+ if( use_rev1 == NULL || RCS_isdead( vers->srcfile, use_rev1 ) )
{
/* The first revision does not exist. If EMPTY_FILES is
true, treat this as an added file. Otherwise, warn
about the missing tag. */
- if (use_rev2 == NULL)
+ if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) )
/* At least in the case where DIFF_REV1 and DIFF_REV2
- are both numeric, we should be returning some kind
- of error (see basicb-8a0 in testsuite). The symbolic
- case may be more complicated. */
+ * are both numeric (and non-existant (NULL), as opposed to
+ * dead?), we should be returning some kind of error (see
+ * basicb-8a0 in testsuite). The symbolic case may be more
+ * complicated.
+ */
return DIFF_SAME;
- else if (empty_files)
+ if( empty_files )
return DIFF_ADDED;
+ if( use_rev1 != NULL )
+ {
+ if (diff_rev1)
+ {
+ error( 0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev1, finfo->fullname );
+ }
+ else
+ {
+ error( 0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date1, finfo->fullname );
+ }
+ error( 0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name );
+ }
else if (diff_rev1)
error (0, 0, "tag %s is not in file %s", diff_rev1,
finfo->fullname);
@@ -970,13 +991,32 @@ diff_file_nodiff (finfo, vers, empty_file)
return DIFF_ERROR;
}
- if (use_rev2 == NULL)
+ assert( use_rev1 != NULL );
+ if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) )
{
/* The second revision does not exist. If EMPTY_FILES is
true, treat this as a removed file. Otherwise warn
about the missing tag. */
if (empty_files)
return DIFF_REMOVED;
+ if( use_rev2 != NULL )
+ {
+ if (diff_rev2)
+ {
+ error( 0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev2, finfo->fullname );
+ }
+ else
+ {
+ error( 0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date2, finfo->fullname );
+ }
+ error( 0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name );
+ }
else if (diff_rev2)
error (0, 0, "tag %s is not in file %s", diff_rev2,
finfo->fullname);
@@ -985,15 +1025,23 @@ diff_file_nodiff (finfo, vers, empty_file)
diff_date2, finfo->fullname);
return DIFF_ERROR;
}
-
- /* now, see if we really need to do the diff */
- if (strcmp (use_rev1, use_rev2) == 0)
+ /* Now, see if we really need to do the diff. We can't assume that the
+ * files are different when the revs are.
+ */
+ assert( use_rev2 != NULL );
+ if( strcmp (use_rev1, use_rev2) == 0 )
return DIFF_SAME;
- else
- return DIFF_DIFFERENT;
+ /* else fall through and do the diff */
}
- if ((diff_rev1 || diff_date1) && use_rev1 == NULL)
+ /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0...
+ * err... ok, then both rev1 & rev2 must have resolved to an existing,
+ * live version due to if statement we just closed.
+ */
+ assert (!(diff_rev2 || diff_date2) || (use_rev1 && use_rev2));
+
+ if ((diff_rev1 || diff_date1) &&
+ (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1)))
{
/* The first revision does not exist, and no second revision
was given. */
@@ -1001,25 +1049,39 @@ diff_file_nodiff (finfo, vers, empty_file)
{
if (empty_file == DIFF_REMOVED)
return DIFF_SAME;
- else
- {
- if (user_file_rev && use_rev2 == NULL)
- use_rev2 = xstrdup (user_file_rev);
- return DIFF_ADDED;
- }
+ if( user_file_rev && use_rev2 == NULL )
+ use_rev2 = xstrdup( user_file_rev );
+ return DIFF_ADDED;
}
- else
+ if( use_rev1 != NULL )
{
if (diff_rev1)
- error (0, 0, "tag %s is not in file %s", diff_rev1,
- finfo->fullname);
+ {
+ error( 0, 0,
+ "Tag %s refers to a dead (removed) revision in file `%s'.",
+ diff_rev1, finfo->fullname );
+ }
else
- error (0, 0, "no revision for date %s in file %s",
- diff_date1, finfo->fullname);
- return DIFF_ERROR;
+ {
+ error( 0, 0,
+ "Date %s refers to a dead (removed) revision in file `%s'.",
+ diff_date1, finfo->fullname );
+ }
+ error( 0, 0,
+ "No comparison available. Pass `-N' to `%s diff'?",
+ program_name );
}
+ else if ( diff_rev1 )
+ error( 0, 0, "tag %s is not in file %s", diff_rev1,
+ finfo->fullname );
+ else
+ error( 0, 0, "no revision for date %s in file %s",
+ diff_date1, finfo->fullname );
+ return DIFF_ERROR;
}
+ assert( !diff_rev1 || use_rev1 );
+
if (user_file_rev)
{
/* drop user_file_rev into first unused use_rev */
@@ -1028,20 +1090,25 @@ diff_file_nodiff (finfo, vers, empty_file)
else if (!use_rev2)
use_rev2 = xstrdup (user_file_rev);
/* and if not, it wasn't needed anyhow */
- user_file_rev = 0;
+ user_file_rev = NULL;
}
- /* now, see if we really need to do the diff */
- if (use_rev1 && use_rev2)
+ /* Now, see if we really need to do the diff. We can't assume that the
+ * files are different when the revs are.
+ */
+ if( use_rev1 && use_rev2)
{
if (strcmp (use_rev1, use_rev2) == 0)
return DIFF_SAME;
- else
- return DIFF_DIFFERENT;
+ /* Fall through and do the diff. */
}
-
- if (use_rev1 == NULL
- || (vers->vn_user != NULL && strcmp (use_rev1, vers->vn_user) == 0))
+ /* Don't want to do the timestamp check with both use_rev1 & use_rev2 set.
+ * The timestamp check is just for the default case of diffing the
+ * workspace file against its base revision.
+ */
+ else if( use_rev1 == NULL
+ || ( vers->vn_user != NULL
+ && strcmp( use_rev1, vers->vn_user ) == 0 ) )
{
if (empty_file == DIFF_DIFFERENT
&& vers->ts_user != NULL
@@ -1066,13 +1133,12 @@ diff_file_nodiff (finfo, vers, empty_file)
return empty_file;
/*
- * with 0 or 1 -r option specified, run a quick diff to see if we
- * should bother with it at all.
+ * Run a quick cmp to see if we should bother with a full diff.
*/
- retcode = RCS_cmp_file (vers->srcfile, use_rev1,
- *options ? options : vers->options,
- finfo->file);
+ retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache,
+ use_rev2, *options ? options : vers->options,
+ finfo->file );
return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
}
diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c
index d506836..98cb006 100644
--- a/contrib/cvs/src/entries.c
+++ b/contrib/cvs/src/entries.c
@@ -27,6 +27,8 @@ static Entnode *subdir_record PROTO((int, const char *, const char *));
static FILE *entfile;
static char *entfilename; /* for error messages */
+
+
/*
* Construct an Entnode
*/
@@ -93,9 +95,7 @@ write_ent_proc (node, closure)
Node *node;
void *closure;
{
- Entnode *entnode;
-
- entnode = (Entnode *) node->data;
+ Entnode *entnode = node->data;
if (closure != NULL && entnode->type != ENT_FILE)
*(int *) closure = 1;
@@ -148,7 +148,7 @@ write_entries (list)
/* We didn't write out any directories. Check the list
private data to see whether subdirectory information is
known. If it is, we need to write out an empty D line. */
- sdtp = (struct stickydirtag *) list->list->data;
+ sdtp = list->list->data;
if (sdtp == NULL || sdtp->subdirs)
if (fprintf (entfile, "D\n") < 0)
error (1, errno, "cannot write %s", entfilename);
@@ -165,13 +165,15 @@ write_entries (list)
error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
}
+
+
/*
* Removes the argument file from the Entries file if necessary.
*/
void
Scratch_Entry (list, fname)
List *list;
- char *fname;
+ const char *fname;
{
Node *node;
@@ -205,6 +207,8 @@ Scratch_Entry (list, fname)
}
}
+
+
/*
* Enters the given file name/version/time-stamp into the Entries file,
* removing the old entry first, if necessary.
@@ -212,13 +216,13 @@ Scratch_Entry (list, fname)
void
Register (list, fname, vn, ts, options, tag, date, ts_conflict)
List *list;
- char *fname;
- char *vn;
- char *ts;
- char *options;
- char *tag;
- char *date;
- char *ts_conflict;
+ const char *fname;
+ const char *vn;
+ const char *ts;
+ const char *options;
+ const char *tag;
+ const char *date;
+ const char *ts_conflict;
{
Entnode *entnode;
Node *node;
@@ -273,9 +277,8 @@ static void
freesdt (p)
Node *p;
{
- struct stickydirtag *sdtp;
+ struct stickydirtag *sdtp = p->data;
- sdtp = (struct stickydirtag *) p->data;
if (sdtp->tag)
free (sdtp->tag);
if (sdtp->date)
@@ -491,7 +494,7 @@ Entries_Open (aflag, update_dir)
sdtp->nonbranch = dirnonbranch;
/* feed it into the list-private area */
- entries->list->data = (char *) sdtp;
+ entries->list->data = sdtp;
entries->list->delproc = freesdt;
}
@@ -556,7 +559,7 @@ Entries_Open (aflag, update_dir)
sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
memset ((char *) sdtp, 0, sizeof (*sdtp));
sdtp->subdirs = 0;
- entries->list->data = (char *) sdtp;
+ entries->list->data = sdtp;
entries->list->delproc = freesdt;
}
@@ -595,9 +598,8 @@ static void
Entries_delproc (node)
Node *node;
{
- Entnode *p;
+ Entnode *p = node->data;
- p = (Entnode *) node->data;
Entnode_Destroy(p);
}
@@ -629,7 +631,7 @@ AddEntryNode (list, entdata)
assume that the key is dynamically allocated. The user's free proc
should be responsible for freeing the key. */
p->key = xstrdup (entdata->user);
- p->data = (char *) entdata;
+ p->data = entdata;
/* put the node into the list */
addnode (list, p);
@@ -711,12 +713,12 @@ WriteTemplate (dir, update_dir)
*/
void
WriteTag (dir, tag, date, nonbranch, update_dir, repository)
- char *dir;
- char *tag;
- char *date;
+ const char *dir;
+ const char *tag;
+ const char *date;
int nonbranch;
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
{
FILE *fout;
char *tmp;
@@ -869,11 +871,10 @@ void
Subdirs_Known (entries)
List *entries;
{
- struct stickydirtag *sdtp;
+ struct stickydirtag *sdtp = entries->list->data;
/* If there is no list private data, that means that the
subdirectory information is known. */
- sdtp = (struct stickydirtag *) entries->list->data;
if (sdtp != NULL && ! sdtp->subdirs)
{
FILE *fp;
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
index 01afa93..bf5be5e 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -331,12 +331,13 @@ make_directories (name)
existed. */
int
mkdir_if_needed (name)
- char *name;
+ const char *name;
{
if (mkdir (name, 0777) < 0)
{
- if (errno != EEXIST && !isdir (name))
- error (1, errno, "cannot make directory %s", name);
+ int save_errno = errno;
+ if (save_errno != EEXIST && !isdir (name))
+ error (1, save_errno, "cannot make directory %s", name);
return 1;
}
return 0;
@@ -351,7 +352,7 @@ mkdir_if_needed (name)
*/
void
xchmod (fname, writable)
- char *fname;
+ const char *fname;
int writable;
{
struct stat sb;
@@ -613,6 +614,7 @@ xcmp (file1, file2)
/* If FILE1 and FILE2 are symlinks, they are equal if they point to
the same thing. */
+#ifdef S_ISLNK
if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode))
{
int result;
@@ -623,6 +625,7 @@ xcmp (file1, file2)
free (buf2);
return result;
}
+#endif
/* If FILE1 and FILE2 are devices, they are equal if their device
numbers match. */
@@ -770,8 +773,8 @@ FILE *cvs_temp_file (filename)
if (fd == -1) fp = NULL;
else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
{
- /* attempt to close and unlink the file since mkstemp returned sucessfully and
- * we believe it's been created and opened
+ /* Attempt to close and unlink the file since mkstemp returned
+ * sucessfully and we believe it's been created and opened.
*/
int save_errno = errno;
if (close (fd))
@@ -849,31 +852,33 @@ FILE *cvs_temp_file (filename)
return fp;
}
-/* Return non-zero iff FILENAME is absolute.
- Trivial under Unix, but more complicated under other systems. */
-int
-isabsolute (filename)
- const char *filename;
-{
- return filename[0] == '/';
-}
-/*
- * Return a string (dynamically allocated) with the name of the file to which
- * LINK is symlinked.
+
+#ifdef HAVE_READLINK
+/* char *
+ * xreadlink ( const char *link )
+ *
+ * Like the X/OPEN and 4.4BSD readlink() function, but allocates and returns
+ * its own buf.
+ *
+ * INPUTS
+ * link The original path.
+ *
+ * RETURNS
+ * The resolution of the final symbolic link in the path.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
*/
char *
xreadlink (link)
const char *link;
{
char *file = NULL;
- char *tfile;
int buflen = BUFSIZ;
int linklen;
- if (!islink (link))
- return NULL;
-
/* Get the name of the file to which `from' is linked.
FIXME: what portability issues arise here? Are readlink &
ENAMETOOLONG defined on all systems? -twp */
@@ -890,19 +895,59 @@ xreadlink (link)
error (1, errno, "cannot readlink %s", link);
file[linklen] = '\0';
- tfile = xstrdup (file);
- free (file);
+ return file;
+}
+#endif /* HAVE_READLINK */
+
- return tfile;
+
+/* char *
+ * xresolvepath ( const char *path )
+ *
+ * Like xreadlink(), but resolve all links in a path.
+ *
+ * INPUTS
+ * path The original path.
+ *
+ * RETURNS
+ * The path with any symbolic links expanded.
+ *
+ * ERRORS
+ * This function exits with a fatal error if it fails to read the link for
+ * any reason.
+ */
+char *
+xresolvepath ( path )
+ const char *path;
+{
+ char *hardpath;
+ char *owd;
+
+ assert ( isdir ( path ) );
+
+ /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
+ * bit by bit calling xreadlink().
+ */
+
+ owd = xgetwd();
+ if ( CVS_CHDIR ( path ) < 0)
+ error ( 1, errno, "cannot chdir to %s", path );
+ if ( ( hardpath = xgetwd() ) == NULL )
+ error (1, errno, "cannot getwd in %s", path);
+ if ( CVS_CHDIR ( owd ) < 0)
+ error ( 1, errno, "cannot chdir to %s", owd );
+ free (owd);
+ return hardpath;
}
+
/* Return a pointer into PATH's last component. */
-char *
+const char *
last_component (path)
- char *path;
+ const char *path;
{
- char *last = strrchr (path, '/');
+ const char *last = strrchr (path, '/');
if (last && (last != path))
return last + 1;
@@ -994,6 +1039,8 @@ expand_wild (argc, argv, pargc, pargv)
(*pargv)[i] = xstrdup (argv[i]);
}
+
+
#ifdef SERVER_SUPPORT
/* Case-insensitive string compare. I know that some systems
have such a routine, but I'm not sure I see any reasons for
@@ -1002,11 +1049,11 @@ expand_wild (argc, argv, pargc, pargv)
not). */
int
cvs_casecmp (str1, str2)
- char *str1;
- char *str2;
+ const char *str1;
+ const char *str2;
{
- char *p;
- char *q;
+ const char *p;
+ const char *q;
int pqdiff;
p = str1;
@@ -1020,107 +1067,4 @@ cvs_casecmp (str1, str2)
}
return pqdiff;
}
-
-/* Case-insensitive file open. As you can see, this is an expensive
- call. We don't regard it as our main strategy for dealing with
- case-insensitivity. Returns errno code or 0 for success. Puts the
- new file in *FP. NAME and MODE are as for fopen. If PATHP is not
- NULL, then put a malloc'd string containing the pathname as found
- into *PATHP. *PATHP is only set if the return value is 0.
-
- Might be cleaner to separate the file finding (which just gives
- *PATHP) from the file opening (which the caller can do). For one
- thing, might make it easier to know whether to put NAME or *PATHP
- into error messages. */
-int
-fopen_case (name, mode, fp, pathp)
- char *name;
- char *mode;
- FILE **fp;
- char **pathp;
-{
- struct dirent *dp;
- DIR *dirp;
- char *dir;
- char *fname;
- char *found_name;
- int retval;
-
- /* Separate NAME into directory DIR and filename within the directory
- FNAME. */
- dir = xstrdup (name);
- fname = strrchr (dir, '/');
- if (fname == NULL)
- error (1, 0, "internal error: relative pathname in fopen_case");
- *fname++ = '\0';
-
- found_name = NULL;
- dirp = CVS_OPENDIR (dir);
- if (dirp == NULL)
- {
- if (existence_error (errno))
- {
- /* This can happen if we are looking in the Attic and the Attic
- directory does not exist. Return the error to the caller;
- they know what to do with it. */
- retval = errno;
- goto out;
- }
- else
- {
- /* Give a fatal error; that way the error message can be
- more specific than if we returned the error to the caller. */
- error (1, errno, "cannot read directory %s", dir);
- }
- }
- errno = 0;
- while ((dp = CVS_READDIR (dirp)) != NULL)
- {
- if (cvs_casecmp (dp->d_name, fname) == 0)
- {
- if (found_name != NULL)
- error (1, 0, "%s is ambiguous; could mean %s or %s",
- fname, dp->d_name, found_name);
- found_name = xstrdup (dp->d_name);
- }
- }
- if (errno != 0)
- error (1, errno, "cannot read directory %s", dir);
- CVS_CLOSEDIR (dirp);
-
- if (found_name == NULL)
- {
- *fp = NULL;
- retval = ENOENT;
- }
- else
- {
- char *p;
-
- /* Copy the found name back into DIR. We are assuming that
- found_name is the same length as fname, which is true as
- long as the above code is just ignoring case and not other
- aspects of filename syntax. */
- p = dir + strlen (dir);
- *p++ = '/';
- strcpy (p, found_name);
- *fp = fopen (dir, mode);
- if (*fp == NULL)
- retval = errno;
- else
- retval = 0;
- }
-
- if (pathp == NULL)
- free (dir);
- else if (retval != 0)
- free (dir);
- else
- *pathp = dir;
- free (found_name);
- out:
- return retval;
-}
#endif /* SERVER_SUPPORT */
-/* vim:tabstop=8:shiftwidth=4
- */
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 5206d0e..b962ebc 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -22,7 +22,7 @@
#include "savecwd.h"
#include <assert.h>
-static char *get_comment PROTO((char *user));
+static char *get_comment PROTO((const char *user));
static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
char *vers));
static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
@@ -93,7 +93,7 @@ import (argc, argv)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
- command_name);
+ cvs_cmd_name);
break;
case 'd':
#ifdef SERVER_SUPPORT
@@ -159,6 +159,21 @@ import (argc, argv)
use_file_modtime = 1;
#endif
+ /* Don't allow "CVS" as any directory in module path.
+ *
+ * Could abstract this to valid_module_path, but I don't think we'll need
+ * to call it from anywhere else.
+ */
+ if ((cp = strstr(argv[0], "CVS")) && /* path contains "CVS" AND ... */
+ ((cp == argv[0]) || ISDIRSEP(*(cp-1))) && /* /^CVS/ OR m#/CVS# AND ... */
+ ((*(cp+3) == '\0') || ISDIRSEP(*(cp+3))) /* /CVS$/ OR m#CVS/# */
+ )
+ {
+ error (0, 0,
+ "The word `CVS' is reserved by CVS and may not be used");
+ error (1, 0, "as a directory in a path or as a file name.");
+ }
+
for (i = 1; i < argc; i++) /* check the tags for validity */
{
int j;
@@ -170,8 +185,7 @@ import (argc, argv)
}
/* XXX - this should be a module, not just a pathname */
- if (! isabsolute (argv[0])
- && pathname_levels (argv[0]) == 0)
+ if (!isabsolute (argv[0]) && pathname_levels (argv[0]) == 0)
{
if (current_parsed_root == NULL)
{
@@ -381,7 +395,7 @@ import (argc, argv)
li->type = T_TITLE;
li->tag = xstrdup (vbranch);
li->rev_old = li->rev_new = NULL;
- p->data = (char *) li;
+ p->data = li;
(void) addnode (ulist, p);
Update_Logfile (repository, message, logfp, ulist);
dellist (&ulist);
@@ -575,7 +589,8 @@ process_import_file (message, vfile, vtag, targc, targv)
node = findnode_fn (entries, vfile);
if (node != NULL)
{
- Entnode *entdata = (Entnode *) node->data;
+ Entnode *entdata = node->data;
+
if (entdata->type == ENT_FILE)
{
assert (entdata->options[0] == '-'
@@ -655,7 +670,8 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
not NULL? */
expand = vers->srcfile->expand != NULL &&
vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
- different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, expand, vfile);
+ different = RCS_cmp_file( vers->srcfile, vers->vn_rcs, (char **)NULL,
+ (char *)NULL, expand, vfile );
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
@@ -934,7 +950,7 @@ static const struct compair comtable[] =
static char *
get_comment (user)
- char *user;
+ const char *user;
{
char *cp, *suffix;
char *suffix_path;
@@ -990,34 +1006,34 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
add_vbranch, vtag, targc, targv,
desctext, desclen, add_logfp)
/* Log message for the addition. Not used if add_vhead == NULL. */
- char *message;
+ const char *message;
/* Filename of the RCS file to create. */
- char *rcs;
+ const char *rcs;
/* Filename of the file to serve as the contents of the initial
revision. Even if add_vhead is NULL, we use this to determine
the modes to give the new RCS file. */
- char *user;
+ const char *user;
/* Revision number of head that we are adding. Normally 1.1 but
could be another revision as long as ADD_VBRANCH is a branch
from it. If NULL, then just add an empty file without any
revisions (similar to the one created by "rcs -i"). */
- char *add_vhead;
+ const char *add_vhead;
/* Keyword expansion mode, e.g., "b" for binary. NULL means the
default behavior. */
- char *key_opt;
+ const char *key_opt;
/* Vendor branch to import to, or NULL if none. If non-NULL, then
vtag should also be non-NULL. */
- char *add_vbranch;
- char *vtag;
+ const char *add_vbranch;
+ const char *vtag;
int targc;
char *targv[];
/* If non-NULL, description for the file. If NULL, the description
will be empty. */
- char *desctext;
+ const char *desctext;
size_t desclen;
/* Write errors to here as well as via error (), or NULL if we should
@@ -1033,8 +1049,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
int i, ierrno, err = 0;
mode_t mode;
char *tocvsPath;
- char *userfile;
- char *local_opt = key_opt;
+ const char *userfile;
char *free_opt = NULL;
mode_t file_type;
@@ -1048,11 +1063,11 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
or the other. Before making a change of this sort, should think
about what is best, document it (in cvs.texinfo and NEWS), &c. */
- if (local_opt == NULL)
+ if (key_opt == NULL)
{
if (wrap_name_has (user, WRAP_RCSOPTION))
{
- local_opt = free_opt = wrap_rcsoption (user, 0);
+ key_opt = free_opt = wrap_rcsoption (user, 0);
}
}
@@ -1089,7 +1104,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (!preserve_perms || file_type == S_IFREG)
{
fpuser = CVS_FOPEN (userfile,
- ((local_opt != NULL && strcmp (local_opt, "b") == 0)
+ ((key_opt != NULL && strcmp (key_opt, "b") == 0)
? "rb"
: "r")
);
@@ -1159,9 +1174,9 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
goto write_error;
}
- if (local_opt != NULL && strcmp (local_opt, "kv") != 0)
+ if (key_opt != NULL && strcmp (key_opt, "kv") != 0)
{
- if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0)
+ if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0)
{
goto write_error;
}
@@ -1465,19 +1480,16 @@ read_error:
*/
int
expand_at_signs (buf, size, fp)
- char *buf;
+ const char *buf;
off_t size;
FILE *fp;
{
- register char *cp, *next;
+ register const char *cp, *next;
cp = buf;
while ((next = memchr (cp, '@', size)) != NULL)
{
- int len;
-
- ++next;
- len = next - cp;
+ size_t len = ++next - cp;
if (fwrite (cp, 1, len, fp) != len)
return EOF;
if (putc ('@', fp) == EOF)
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 89ca9e4..36cbf7d 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -57,26 +57,28 @@
1. Check for EROFS. Maybe useful, although in the presence of NFS
EROFS does *not* mean that the file system is unchanging.
- 2. Provide a means to put the cvs locks in some directory apart from
- the repository (CVSROOT/locks; a -l option in modules; etc.).
-
- 3. Provide an option to disable locks for operations which only
+ 2. Provide an option to disable locks for operations which only
read (see above for some of the consequences).
- 4. Have a server internally do the locking. Probably a good
+ 3. Have a server internally do the locking. Probably a good
long-term solution, and many people have been working hard on code
changes which would eventually make it possible to have a server
which can handle various connections in one process, but there is
- much, much work still to be done before this is feasible.
-
- 5. Like #4 but use shared memory or something so that the servers
- merely need to all be on the same machine. This is a much smaller
- change to CVS (it functions much like #2; shared memory might be an
- unneeded complication although it presumably would be faster). */
+ much, much work still to be done before this is feasible. */
#include "cvs.h"
#include <assert.h>
+#ifdef HAVE_NANOSLEEP
+# include "xtime.h"
+#else /* HAVE_NANOSLEEP */
+# if !defined HAVE_USLEEP && defined HAVE_SELECT
+ /* use select as a workaround */
+# include "xselect.h"
+# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */
+#endif /* !HAVE_NANOSLEEP */
+
+
struct lock {
/* This is the directory in which we may have a lock named by the
readlock variable, a lock named by the writelock variable, and/or
@@ -343,7 +345,7 @@ unlock_proc (p, closure)
Node *p;
void *closure;
{
- lock_simple_remove ((struct lock *)p->data);
+ lock_simple_remove (p->data);
return (0);
}
@@ -390,6 +392,8 @@ lock_simple_remove (lock)
}
}
+
+
/*
* Create a lock file for readers
*/
@@ -406,13 +410,13 @@ Reader_Lock (xrepository)
xrepository);
if (noexec || readonlyfs)
- return (0);
+ return 0;
/* we only do one directory at a time for read locks! */
if (global_readlock.repository != NULL)
{
error (0, 0, "Reader_Lock called while read locks set - Help!");
- return (1);
+ return 1;
}
if (readlock == NULL)
@@ -441,7 +445,7 @@ Reader_Lock (xrepository)
/* We don't set global_readlock.repository to NULL. I think this
only works because recurse.c will give a fatal error if we return
a nonzero value. */
- return (1);
+ return 1;
}
/* write a read-lock */
@@ -460,9 +464,11 @@ Reader_Lock (xrepository)
/* free the lock dir */
clear_lock (&global_readlock);
- return (err);
+ return err;
}
+
+
/*
* Lock a list of directories for writing
*/
@@ -478,7 +484,7 @@ Writer_Lock (list)
char *wait_repos;
if (noexec)
- return (0);
+ return 0;
if (readonlyfs) {
error (0, 0, "write lock failed - read-only repository");
@@ -489,7 +495,7 @@ Writer_Lock (list)
if (locklist != (List *) NULL)
{
error (0, 0, "Writer_Lock called while write locks set - Help!");
- return (1);
+ return 1;
}
wait_repos = NULL;
@@ -512,7 +518,7 @@ Writer_Lock (list)
free (wait_repos);
Lock_Cleanup (); /* clean up any locks we set */
error (0, 0, "lock failed - giving up");
- return (1);
+ return 1;
case L_LOCKED: /* Someone already had a lock */
remove_locks (); /* clean up any locks we set */
@@ -526,18 +532,20 @@ Writer_Lock (list)
lock_obtained (wait_repos);
free (wait_repos);
}
- return (0);
+ return 0;
default:
if (wait_repos != NULL)
free (wait_repos);
error (0, 0, "unknown lock status %d in Writer_Lock",
lock_error);
- return (1);
+ return 1;
}
}
}
+
+
/*
* walklist proc for setting write locks
*/
@@ -548,14 +556,16 @@ set_writelock_proc (p, closure)
{
/* if some lock was not OK, just skip this one */
if (lock_error != L_OK)
- return (0);
+ return 0;
/* apply the write lock */
lock_error_repos = p->key;
- lock_error = write_lock ((struct lock *)p->data);
- return (0);
+ lock_error = write_lock (p->data);
+ return 0;
}
+
+
/*
* Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if
* lock held by someone else or L_ERROR if an error occurred
@@ -598,7 +608,7 @@ write_lock (lock)
}
/* indicate we failed due to read locks instead of error */
- return (L_LOCKED);
+ return L_LOCKED;
}
/* write the write-lock file */
@@ -620,15 +630,17 @@ write_lock (lock)
error (0, xerrno, "cannot create write lock in repository `%s'",
lock->repository);
free (tmp);
- return (L_ERROR);
+ return L_ERROR;
}
free (tmp);
- return (L_OK);
+ return L_OK;
}
else
- return (status);
+ return status;
}
+
+
/*
* readers_exist() returns 0 if there are no reader lock files remaining in
* the repository; else 1 is returned, to indicate that the caller should
@@ -638,6 +650,7 @@ static int
readers_exist (repository)
char *repository;
{
+ char *lockdir;
char *line;
DIR *dirp;
struct dirent *dp;
@@ -645,12 +658,15 @@ readers_exist (repository)
int ret;
#ifdef CVS_FUDGELOCKS
time_t now;
- (void) time (&now);
+ (void)time (&now);
#endif
+ lockdir = lock_name (repository, "");
+ lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */
+
do {
- if ((dirp = CVS_OPENDIR (repository)) == NULL)
- error (1, 0, "cannot open directory %s", repository);
+ if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
+ error (1, 0, "cannot open directory %s", lockdir);
ret = 0;
errno = 0;
@@ -658,13 +674,9 @@ readers_exist (repository)
{
if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0)
{
- /* ignore our own readlock, if any */
- if (readlock && strcmp (readlock, dp->d_name) == 0)
- continue;
-
- line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5);
- (void) sprintf (line, "%s/%s", repository, dp->d_name);
- if ( CVS_STAT (line, &sb) != -1)
+ line = xmalloc (strlen (lockdir) + 1 + strlen (dp->d_name) + 1);
+ (void)sprintf (line, "%s/%s", lockdir, dp->d_name);
+ if (CVS_STAT (line, &sb) != -1)
{
#ifdef CVS_FUDGELOCKS
/*
@@ -684,9 +696,10 @@ readers_exist (repository)
}
else
{
- /* If the file doesn't exist, it just means that it disappeared
- between the time we did the readdir and the time we did
- the stat. */
+ /* If the file doesn't exist, it just means that it
+ * disappeared between the time we did the readdir and the
+ * time we did the stat.
+ */
if (!existence_error (errno))
error (0, errno, "cannot stat %s", line);
}
@@ -702,9 +715,14 @@ readers_exist (repository)
CVS_CLOSEDIR (dirp);
} while (ret < 0);
- return (ret);
+
+ if (lockdir != NULL)
+ free (lockdir);
+ return ret;
}
+
+
/*
* Set the static variable lockers_name appropriately, based on the stat
* structure passed in.
@@ -717,22 +735,29 @@ set_lockers_name (statp)
if (lockers_name != NULL)
free (lockers_name);
- if ((pw = (struct passwd *) getpwuid (statp->st_uid)) !=
- (struct passwd *) NULL)
+ if ((pw = (struct passwd *)getpwuid (statp->st_uid)) !=
+ (struct passwd *)NULL)
{
lockers_name = xstrdup (pw->pw_name);
}
else
{
lockers_name = xmalloc (20);
- (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
+ (void)sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
}
}
+
+
/*
- * Persistently tries to make the directory "lckdir",, which serves as a
- * lock. If the create time on the directory is greater than CVSLCKAGE
+ * Persistently tries to make the directory "lckdir", which serves as a
+ * lock.
+ *
+ * #ifdef CVS_FUDGELOCKS
+ * If the create time on the directory is greater than CVSLCKAGE
* seconds old, just try to remove the directory.
+ * #endif
+ *
*/
static int
set_lock (lock, will_wait)
@@ -740,6 +765,7 @@ set_lock (lock, will_wait)
int will_wait;
{
int waited;
+ long us;
struct stat sb;
mode_t omask;
#ifdef CVS_FUDGELOCKS
@@ -756,6 +782,7 @@ set_lock (lock, will_wait)
* directory before they exit.
*/
waited = 0;
+ us = 1;
lock->have_lckdir = 0;
for (;;)
{
@@ -817,6 +844,33 @@ set_lock (lock, will_wait)
/* if he wasn't willing to wait, return an error */
if (!will_wait)
return (L_LOCKED);
+
+ /* if possible, try a very short sleep without a message */
+ if (!waited && us < 1000)
+ {
+ us += us;
+#if defined HAVE_NANOSLEEP
+ {
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = us * 1000;
+ (void)nanosleep (&ts, NULL);
+ continue;
+ }
+#elif defined HAVE_USLEEP
+ (void)usleep (us);
+ continue;
+#elif defined HAVE_SELECT
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = us;
+ (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);
+ continue;
+ }
+#endif
+ }
+
lock_wait (lock->repository);
waited = 1;
}
@@ -884,10 +938,13 @@ lock_obtained (repos)
cvs_flusherr ();
free (msg);
}
-
+
+
+
static int lock_filesdoneproc PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
+ const char *repository,
+ const char *update_dir,
+ List *entries));
/*
* Create a list of repositories to lock
@@ -897,8 +954,8 @@ static int
lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
Node *p;
@@ -924,16 +981,15 @@ lock_tree_for_write (argc, argv, local, which, aflag)
int which;
int aflag;
{
- int err;
/*
* Run the recursion processor to find all the dirs to lock and lock all
* the dirs
*/
lock_tree_list = getlist ();
- err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
- argv, local, which, aflag, CVS_LOCK_NONE,
- (char *) NULL, 0);
+ start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
+ argv, local, which, aflag, CVS_LOCK_NONE,
+ (char *) NULL, 0, (char *) NULL);
sortlist (lock_tree_list, fsortcmp);
if (Writer_Lock (lock_tree_list) != 0)
error (1, 0, "lock failed - giving up");
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
index 58b2c7a..2b8bbea 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -14,12 +14,6 @@
#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
@@ -27,9 +21,6 @@
declaration won't work (some Crays declare the 2#$@% thing as
varadic, believe it or not). On Cray, getpass will be declared
in either stdlib.h or unistd.h. */
-#ifndef _CRAY
-extern char *GETPASS ();
-#endif
#ifndef CVS_PASSWORD_FILE
#define CVS_PASSWORD_FILE ".cvspass"
@@ -231,8 +222,10 @@ password_entry_parseline (cvsroot_canonical, warn, linenumber, linebuf)
*
* Mode Action
* password_entry_lookup Return the password
- * password_entry_delete Delete the entry from the file, if it exists
- * password_entry_add Replace the line with the new one, else append it
+ * password_entry_delete Delete the entry from the file, if it
+ * exists.
+ * password_entry_add Replace the line with the new one, else
+ * append it.
*
* Because the user might be accessing multiple repositories, with
* different passwords for each one, the format of ~/.cvspass is:
@@ -293,7 +286,7 @@ password_entry_operation (operation, root, newpassword)
char *cvsroot_canonical = NULL;
char *password = NULL;
int line_length;
- long line;
+ long line = -1;
char *linebuf = NULL;
size_t linebuf_len;
char *p;
@@ -301,7 +294,8 @@ password_entry_operation (operation, root, newpassword)
if (root->method != pserver_method)
{
- error (0, 0, "internal error: can only call password_entry_operation with pserver method");
+ error (0, 0, "\
+internal error: can only call password_entry_operation with pserver method");
error (1, 0, "CVSROOT: %s", root->original);
}
@@ -325,7 +319,8 @@ password_entry_operation (operation, root, newpassword)
while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
{
line++;
- password = password_entry_parseline(cvsroot_canonical, 1, line, linebuf);
+ password = password_entry_parseline (cvsroot_canonical, 1, line,
+ linebuf);
if (password != NULL)
/* this is it! break out and deal with linebuf */
break;
@@ -375,7 +370,8 @@ process:
* add
*/
if (!noexec && password != NULL && (operation == password_entry_delete
- || (operation == password_entry_add && strcmp (password, newpassword))))
+ || (operation == password_entry_add
+ && strcmp (password, newpassword))))
{
long found_at = line;
char *tmp_name;
@@ -396,7 +392,8 @@ process:
line++;
if (line < found_at
|| (line != found_at
- && !password_entry_parseline(cvsroot_canonical, 0, line, linebuf)))
+ && !password_entry_parseline (cvsroot_canonical, 0, line,
+ linebuf)))
{
if (fprintf (tmp_fp, "%s", linebuf) == EOF)
{
@@ -543,7 +540,7 @@ login (argc, argv)
else
{
char *tmp;
- tmp = GETPASS ("CVS password: ");
+ tmp = getpass ("CVS password: ");
/* Must deal with a NULL return value here. I haven't managed to
* disconnect the CVS process from the tty and force a NULL return
* in sanity.sh, but the Linux version of getpass is documented
@@ -562,7 +559,8 @@ login (argc, argv)
connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0);
- password_entry_operation (password_entry_add, current_parsed_root, typed_password);
+ password_entry_operation (password_entry_add, current_parsed_root,
+ typed_password);
memset (typed_password, 0, strlen (typed_password));
free (typed_password);
@@ -574,6 +572,8 @@ login (argc, argv)
return 0;
}
+
+
/* Returns the _scrambled_ password. The server must descramble
before hashing and comparing. If password file not found, or
password not found in the file, just return NULL. */
@@ -581,7 +581,7 @@ char *
get_cvs_password ()
{
if (current_parsed_root->password)
- return (scramble(current_parsed_root->password));
+ return scramble (current_parsed_root->password);
/* If someone (i.e., login()) is calling connect_to_pserver() out of
context, then assume they have supplied the correct, scrambled
@@ -609,9 +609,12 @@ get_cvs_password ()
error (1, 0, "CVSROOT: %s", current_parsed_root->original);
}
- return password_entry_operation (password_entry_lookup, current_parsed_root, NULL);
+ return password_entry_operation (password_entry_lookup,
+ current_parsed_root, NULL);
}
+
+
static const char *const logout_usage[] =
{
"Usage: %s %s\n",
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index e333663..fbbcc3c 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -15,14 +15,16 @@
static int find_type PROTO((Node * p, void *closure));
static int fmt_proc PROTO((Node * p, void *closure));
-static int logfile_write PROTO((char *repository, char *filter,
- char *message, FILE * logfp, List * changes));
-static int rcsinfo_proc PROTO((char *repository, char *template));
+static int logfile_write PROTO((const char *repository, const char *filter,
+ const char *message, FILE * logfp,
+ List * changes));
+static int rcsinfo_proc PROTO((const char *repository, const char *template));
static int title_proc PROTO((Node * p, void *closure));
-static int update_logfile_proc PROTO((char *repository, char *filter));
+static int update_logfile_proc PROTO((const char *repository,
+ const char *filter));
static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes));
-static int editinfo_proc PROTO((char *repository, char *template));
-static int verifymsg_proc PROTO((char *repository, char *script));
+static int editinfo_proc PROTO((const char *repository, const char *template));
+static int verifymsg_proc PROTO((const char *repository, const char *script));
static FILE *fp;
static char *str_list;
@@ -106,9 +108,8 @@ find_type (p, closure)
Node *p;
void *closure;
{
- struct logfile_info *li;
+ struct logfile_info *li = p->data;
- li = (struct logfile_info *) p->data;
if (li->type == type)
return (1);
else
@@ -127,7 +128,7 @@ fmt_proc (p, closure)
{
struct logfile_info *li;
- li = (struct logfile_info *) p->data;
+ li = p->data;
if (li->type == type)
{
if (li->tag == NULL
@@ -184,9 +185,9 @@ fmt_proc (p, closure)
*/
void
do_editor (dir, messagep, repository, changes)
- char *dir;
+ const char *dir;
char **messagep;
- char *repository;
+ const char *repository;
List *changes;
{
static int reuse_log_message = 0;
@@ -417,7 +418,7 @@ do_editor (dir, messagep, repository, changes)
void
do_verify (messagep, repository)
char **messagep;
- char *repository;
+ const char *repository;
{
FILE *fp;
char *fname;
@@ -433,14 +434,14 @@ do_verify (messagep, repository)
/* FIXME? Do we really want to skip this on noexec? What do we do
for the other administrative files? */
- if (noexec)
+ if (noexec || repository == NULL)
return;
/* Get the name of the verification script to run */
- if (repository != NULL)
- (void) Parse_Info (CVSROOTADM_VERIFYMSG, repository,
- verifymsg_proc, 0);
+ if (Parse_Info (CVSROOTADM_VERIFYMSG, repository, verifymsg_proc, 0) > 0)
+ error (1, 0, "Message verification failed");
+
if (!verifymsg_script)
return;
@@ -554,6 +555,8 @@ do_verify (messagep, repository)
if (unlink_file (fname) < 0)
error (0, errno, "cannot remove %s", fname);
free (fname);
+ free( verifymsg_script );
+ verifymsg_script = NULL;
}
/*
@@ -564,8 +567,8 @@ do_verify (messagep, repository)
/* ARGSUSED */
static int
rcsinfo_proc (repository, template)
- char *repository;
- char *template;
+ const char *repository;
+ const char *template;
{
static char *last_template;
FILE *tfp;
@@ -606,13 +609,13 @@ rcsinfo_proc (repository, template)
* specified program as standard input.
*/
static FILE *logfp;
-static char *message;
+static const char *message;
static List *changes;
void
Update_Logfile (repository, xmessage, xlogfp, xchanges)
- char *repository;
- char *xmessage;
+ const char *repository;
+ const char *xmessage;
FILE *xlogfp;
List *xchanges;
{
@@ -629,17 +632,21 @@ Update_Logfile (repository, xmessage, xlogfp, xchanges)
(void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1);
}
+
+
/*
* callback proc to actually do the logfile write from Update_Logfile
*/
static int
update_logfile_proc (repository, filter)
- char *repository;
- char *filter;
+ const char *repository;
+ const char *filter;
{
- return (logfile_write (repository, filter, message, logfp, changes));
+ return logfile_write (repository, filter, message, logfp, changes);
}
+
+
/*
* concatenate each filename/version onto str_list
*/
@@ -648,10 +655,9 @@ title_proc (p, closure)
Node *p;
void *closure;
{
- struct logfile_info *li;
char *c;
+ struct logfile_info *li = p->data;
- li = (struct logfile_info *) p->data;
if (li->type == type)
{
/* Until we decide on the correct logging solution when we add
@@ -731,9 +737,9 @@ title_proc (p, closure)
*/
static int
logfile_write (repository, filter, message, logfp, changes)
- char *repository;
- char *filter;
- char *message;
+ const char *repository;
+ const char *filter;
+ const char *message;
FILE *logfp;
List *changes;
{
@@ -800,7 +806,7 @@ logfile_write (repository, filter, message, logfp, changes)
if (fmt_percent)
{
int len;
- char *srepos;
+ const char *srepos;
char *fmt_begin, *fmt_end; /* beginning and end of the
format string specified in
filter. */
@@ -931,7 +937,7 @@ logfile_write (repository, filter, message, logfp, changes)
}
setup_tmpfile (pipefp, "", changes);
- (void) fprintf (pipefp, "Log Message:\n%s\n", message);
+ (void) fprintf (pipefp, "Log Message:\n%s\n", (message) ? message : "");
if (logfp != (FILE *) 0)
{
(void) fprintf (pipefp, "Status:\n");
@@ -955,8 +961,8 @@ logfile_write (repository, filter, message, logfp, changes)
/* ARGSUSED */
static int
editinfo_proc(repository, editor)
- char *repository;
- char *editor;
+ const char *repository;
+ const char *editor;
{
/* nothing to do if the last match is the same as this one */
if (editinfo_editor && strcmp (editinfo_editor, editor) == 0)
@@ -973,8 +979,8 @@ editinfo_proc(repository, editor)
*/
static int
verifymsg_proc (repository, script)
- char *repository;
- char *script;
+ const char *repository;
+ const char *script;
{
if (verifymsg_script && strcmp (verifymsg_script, script) == 0)
return (0);
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index dbc2ee2..d00bddd 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -23,9 +23,9 @@
extern int gethostname ();
#endif
-char *program_name;
-char *program_path;
-char *command_name;
+const char *program_name;
+const char *program_path;
+const char *cvs_cmd_name;
/* I'd dynamically allocate this, but it seems like gethostname
requires a fixed size array. If I'm remembering the RFCs right,
@@ -252,7 +252,6 @@ static const char *const opt_usage[] =
" -r Make checked-out files read-only.\n",
" -w Make checked-out files read-write (default).\n",
" -g Force group-write perms on checked-out files.\n",
- " -l Turn history logging off.\n",
" -n Do not execute anything that will change the disk.\n",
" -t Show trace of program execution -- try with -n.\n",
" -R Assume repository is read-only, such as CDROM\n",
@@ -413,7 +412,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 const char short_options[] = "+QqgrwtnRvb:T:e:d:Hfz:s:xaU";
static struct option long_options[] =
{
{"help", 0, NULL, 'H'},
@@ -560,7 +559,6 @@ main (argc, argv)
break;
case 'n':
noexec = 1;
- case 'l': /* Fall through */
logoff = 1;
break;
case 'v':
@@ -568,7 +566,7 @@ main (argc, argv)
version (0, (char **) NULL);
(void) fputs ("\n", stdout);
(void) fputs ("\
-Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
+Copyright (c) 1989-2004 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);
@@ -613,14 +611,19 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
break;
case 'z':
#ifdef CLIENT_SUPPORT
- gzip_level = atoi (optarg);
- if (gzip_level < 0 || gzip_level > 9)
+ gzip_level = strtol (optarg, &end, 10);
+ if (*end != '\0' || gzip_level < 0 || gzip_level > 9)
error (1, 0,
"gzip compression level must be between 0 and 9");
-#endif
+#endif /* CLIENT_SUPPORT */
/* If no CLIENT_SUPPORT, we just silently ignore the gzip
- level, so that users can have it in their .cvsrc and not
- cause any trouble. */
+ * level, so that users can have it in their .cvsrc and not
+ * cause any trouble.
+ *
+ * We still parse the argument to -z for correctness since
+ * one user complained of being bitten by a run of
+ * `cvs -z -n up' which read -n as the argument to -z without
+ * complaining. */
break;
case 's':
variable_set (optarg);
@@ -662,24 +665,24 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
/* Look up the command name. */
- command_name = argv[0];
+ cvs_cmd_name = argv[0];
for (cm = cmds; cm->fullname; cm++)
{
- if (cm->nick1 && !strcmp (command_name, cm->nick1))
+ if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1))
break;
- if (cm->nick2 && !strcmp (command_name, cm->nick2))
+ if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2))
break;
- if (!strcmp (command_name, cm->fullname))
+ if (!strcmp (cvs_cmd_name, cm->fullname))
break;
}
if (!cm->fullname)
{
- fprintf (stderr, "Unknown command: `%s'\n\n", command_name);
+ fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name);
usage (cmd_usage);
}
else
- command_name = cm->fullname; /* Global pointer for later use */
+ cvs_cmd_name = cm->fullname; /* Global pointer for later use */
if (help)
{
@@ -713,18 +716,18 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
running as Kerberos server as root. Do the authentication as
the very first thing, to minimize the amount of time we are
running as root. */
- if (strcmp (command_name, "kserver") == 0)
+ if (strcmp (cvs_cmd_name, "kserver") == 0)
{
kserver_authenticate_connection ();
/* Pretend we were invoked as a plain server. */
- command_name = "server";
+ cvs_cmd_name = "server";
}
# endif /* HAVE_KERBEROS */
# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
- if (strcmp (command_name, "pserver") == 0)
+ if (strcmp (cvs_cmd_name, "pserver") == 0)
{
/* The reason that --allow-root is not a command option
is mainly the comment in server() about how argc,argv
@@ -738,11 +741,11 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
pserver_authenticate_connection ();
/* Pretend we were invoked as a plain server. */
- command_name = "server";
+ cvs_cmd_name = "server";
}
# endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
- server_active = strcmp (command_name, "server") == 0;
+ server_active = strcmp (cvs_cmd_name, "server") == 0;
#endif /* SERVER_SUPPORT */
@@ -815,7 +818,7 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
#endif /* KLUDGE_FOR_WNT_TESTSUITE */
if (use_cvsrc)
- read_cvsrc (&argc, &argv, command_name);
+ read_cvsrc (&argc, &argv, cvs_cmd_name);
#ifdef SERVER_SUPPORT
/* Fiddling with CVSROOT doesn't make sense if we're running
@@ -956,7 +959,7 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
{
save_errno = errno;
/* If this is "cvs init", the root need not exist yet. */
- if (strcmp (command_name, "init") != 0)
+ if (strcmp (cvs_cmd_name, "init") != 0)
{
error (1, save_errno, "%s", path);
}
@@ -1057,7 +1060,11 @@ Copyright (c) 1989-2002 Brian Berliner, david d `zoo' zuhn, \n\
Lock_Cleanup ();
- free (program_path);
+ /* It's okay to cast out the const below since we know we allocated this in
+ * this function. The const was to keep other functions from messing with
+ * this.
+ */
+ free ((char *)program_path);
if (CVSroot_cmdline != NULL)
free (CVSroot_cmdline);
if (free_CVSroot)
@@ -1191,7 +1198,7 @@ void
usage (cpp)
register const char *const *cpp;
{
- (void) fprintf (stderr, *cpp++, program_name, command_name);
+ (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
for (; *cpp; cpp++)
(void) fprintf (stderr, *cpp);
error_exit ();
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index 699ff2a..0c91387 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -9,8 +9,9 @@
*/
#include "cvs.h"
-#include "savecwd.h"
#include "getline.h"
+#include "history.h"
+#include "savecwd.h"
#ifndef DBLKSIZ
#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
@@ -200,7 +201,7 @@ static const char *const checkoutlist_contents[] = {
"#\n",
"# File format:\n",
"#\n",
- "# [<whitespace>]<filename><whitespace><error message><end-of-line>\n",
+ "# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>\n",
"#\n",
"# comment lines begin with '#'\n",
NULL
@@ -299,9 +300,9 @@ static const char *const config_contents[] = {
"# command.\n",
"#TopLevelAdmin=no\n",
"\n",
- "# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n",
+ "# Set `LogHistory' to `all' or `" ALL_HISTORY_REC_TYPES "' to log all transactions to the\n",
"# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
- "#LogHistory=TOFEWGCMAR\n",
+ "#LogHistory=" ALL_HISTORY_REC_TYPES "\n",
"\n",
"# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n",
"# script to change the log message. Set it to `stat' to force CVS to verify",
@@ -463,7 +464,7 @@ mkmodules (dir)
{
/*
* File format:
- * [<whitespace>]<filename><whitespace><error message><end-of-line>
+ * [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>
*
* comment lines begin with '#'
*/
@@ -494,12 +495,13 @@ mkmodules (dir)
}
else
{
+ /* Skip leading white space before the error message. */
for (cp++;
- cp < last && *last && isspace ((unsigned char) *last);
+ cp < last && *cp && isspace ((unsigned char) *cp);
cp++)
;
if (cp < last && *cp)
- error (0, 0, cp, fname);
+ error (0, 0, "%s", cp);
}
if (unlink_file (temp) < 0
&& !existence_error (errno))
@@ -851,7 +853,7 @@ init (argc, argv)
/* Name of ,v file for this administrative file. */
char *info_v;
/* Exit status. */
- int err;
+ int err = 0;
const struct admin_file *fileptr;
@@ -983,5 +985,5 @@ init (argc, argv)
mkmodules (adm);
free (adm);
- return 0;
+ return err;
}
diff --git a/contrib/cvs/src/parseinfo.c b/contrib/cvs/src/parseinfo.c
index 250cd63..38a11c6d 100644
--- a/contrib/cvs/src/parseinfo.c
+++ b/contrib/cvs/src/parseinfo.c
@@ -16,15 +16,16 @@ extern char *logHistory;
/*
* Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
- * the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines
- * matching "ALL", or if no lines match, the last line matching "DEFAULT".
+ * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
+ * lines matching "ALL", or if no lines match, the last line matching
+ * "DEFAULT".
*
* Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
*/
int
Parse_Info (infofile, repository, callproc, all)
- char *infofile;
- char *repository;
+ const char *infofile;
+ const char *repository;
CALLPROC callproc;
int all;
{
@@ -34,9 +35,11 @@ Parse_Info (infofile, repository, callproc, all)
char *line = NULL;
size_t line_allocated = 0;
char *default_value = NULL;
- char *expanded_value= NULL;
+ int default_line = 0;
+ char *expanded_value;
int callback_done, line_number;
- char *cp, *exp, *value, *srepos, bad;
+ char *cp, *exp, *value;
+ const char *srepos;
const char *regex_err;
if (current_parsed_root == NULL)
@@ -116,10 +119,6 @@ Parse_Info (infofile, repository, callproc, all)
if ((cp = strrchr (value, '\n')) != NULL)
*cp = '\0';
- if (expanded_value != NULL)
- free (expanded_value);
- expanded_value = expand_path (value, infofile, line_number);
-
/*
* At this point, exp points to the regular expression, and value
* points to the value to call the callback routine with. Evaluate
@@ -130,12 +129,14 @@ Parse_Info (infofile, repository, callproc, all)
/* save the default value so we have it later if we need it */
if (strcmp (exp, "DEFAULT") == 0)
{
- /* Is it OK to silently ignore all but the last DEFAULT
- expression? */
- if (default_value != NULL && default_value != &bad)
+ if (default_value != NULL)
+ {
+ error (0, 0, "Multiple `DEFAULT' lines (%d and %d) in %s file",
+ default_line, line_number, infofile);
free (default_value);
- default_value = (expanded_value != NULL ?
- xstrdup (expanded_value) : &bad);
+ }
+ default_value = xstrdup(value);
+ default_line = line_number;
continue;
}
@@ -149,8 +150,12 @@ Parse_Info (infofile, repository, callproc, all)
if (!all)
error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
line_number, infofile);
- else if (expanded_value != NULL)
+ else if ((expanded_value = expand_path (value, infofile,
+ line_number)) != NULL)
+ {
err += callproc (repository, expanded_value);
+ free (expanded_value);
+ }
else
err++;
continue;
@@ -171,8 +176,11 @@ Parse_Info (infofile, repository, callproc, all)
continue; /* no match */
/* it did, so do the callback and note that we did one */
- if (expanded_value != NULL)
+ if ((expanded_value = expand_path (value, infofile, line_number)) != NULL)
+ {
err += callproc (repository, expanded_value);
+ free (expanded_value);
+ }
else
err++;
callback_done = 1;
@@ -185,17 +193,18 @@ Parse_Info (infofile, repository, callproc, all)
/* if we fell through and didn't callback at all, do the default */
if (callback_done == 0 && default_value != NULL)
{
- if (default_value != &bad)
- err += callproc (repository, default_value);
+ if ((expanded_value = expand_path (default_value, infofile, default_line)) != NULL)
+ {
+ err += callproc (repository, expanded_value);
+ free (expanded_value);
+ }
else
err++;
}
/* free up space if necessary */
- if (default_value != NULL && default_value != &bad)
+ if (default_value != NULL)
free (default_value);
- if (expanded_value != NULL)
- free (expanded_value);
free (infopath);
if (line != NULL)
free (line);
@@ -211,8 +220,9 @@ Parse_Info (infofile, repository, callproc, all)
KEYWORD=VALUE. There is currently no way to have a multi-line
VALUE (would be nice if there was, probably).
- CVSROOT is the $CVSROOT directory (current_parsed_root->directory might not be
- set yet).
+ CVSROOT is the $CVSROOT directory
+ (current_parsed_root->directory might not be set yet, so this
+ function takes the cvsroot as a function argument).
Returns 0 for success, negative value for failure. Call
error(0, ...) on errors in addition to the return value. */
@@ -287,7 +297,7 @@ parse_config (cvsroot)
for making sure the syntax is consistent. Any good examples
to follow there (Apache?)? */
- /* Strip the training newline. There will be one unless we
+ /* Strip the trailing newline. There will be one unless we
read a partial line without a newline, and then got end of
file (or error?). */
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index ccf3cd5..8aee286 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -64,7 +64,8 @@ struct rcsbuffer
};
static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
-static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
+static char *RCS_getdatebranch PROTO((RCSNode * rcs, const char *date,
+ const char *branch));
static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
const char *filename, unsigned long pos));
static void rcsbuf_close PROTO ((struct rcsbuffer *));
@@ -127,13 +128,13 @@ static void putdeltatext PROTO ((FILE *, Deltatext *));
static FILE *rcs_internal_lockfile PROTO ((char *));
static void rcs_internal_unlockfile PROTO ((FILE *, char *));
-static char *rcs_lockfilename PROTO ((char *));
+static char *rcs_lockfilename PROTO ((const char *));
/* The RCS file reading functions are called a lot, and they do some
string comparisons. This macro speeds things up a bit by skipping
the function call when the first characters are different. It
evaluates its arguments multiple times. */
-#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
+#define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
static char * getfullCVSname PROTO ((char *, char **));
@@ -169,6 +170,81 @@ static const char spacetab[] = {
static char *rcs_lockfile;
static int rcs_lockfd = -1;
+
+
+/*
+ * char *
+ * locate_rcs ( const char* file, const char *repository , int *inattic )
+ *
+ * Find an RCS file in the repository, case insensitively when the cased name
+ * doesn't exist, we are running as the server, and a client has asked us to
+ * ignore case.
+ *
+ * Most parts of CVS will want to rely instead on RCS_parse which calls this
+ * function and is called by recurse.c which then puts the result in useful
+ * places like the rcs field of struct file_info.
+ *
+ * INPUTS
+ *
+ * repository the repository (including the directory)
+ * file the filename within that directory (without RCSEXT).
+ * inattic NULL or a pointer to the output boolean
+ *
+ * OUTPUTS
+ *
+ * inattic If this input was non-null, the destination will be
+ * set to true if the file was found in the attic or
+ * false if not. If no RCS file is found, this value
+ * is undefined.
+ *
+ * RETURNS
+ *
+ * a newly-malloc'd array containing the absolute pathname of the RCS
+ * file that was found or NULL when none was found.
+ *
+ * ERRORS
+ *
+ * errno can be set by the return value of the final call to
+ * locate_file_in_dir(). This should resolve to the system's existence error
+ * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
+ * the Attic was found but no matching files were found in the Attic or its
+ * parent.
+ */
+static char *
+locate_rcs (repository, file, inattic)
+ const char *repository;
+ const char *file;
+ int *inattic;
+{
+ char *retval;
+
+ /* First, try to find the file as cased. */
+ retval = xmalloc (strlen (repository)
+ + sizeof (CVSATTIC)
+ + strlen (file)
+ + sizeof (RCSEXT)
+ + 3);
+ sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
+ if (isreadable (retval))
+ {
+ if (inattic)
+ *inattic = 0;
+ return retval;
+ }
+ sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+ if (isreadable (retval))
+ {
+ if (inattic)
+ *inattic = 1;
+ return retval;
+ }
+ free (retval);
+
+ return NULL;
+}
+
+
+
/* A few generic thoughts on error handling, in particular the
printing of unexpected characters that we find in the RCS file
(that is, why we use '\x%x' rather than %c or some such).
@@ -199,110 +275,36 @@ RCS_parse (file, repos)
{
RCSNode *rcs;
FILE *fp;
- RCSNode *retval;
+ RCSNode *retval = NULL;
char *rcsfile;
+ int inattic;
/* We're creating a new RCSNode, so there is no hope of finding it
in the cache. */
rcsbuf_cache_close ();
- rcsfile = xmalloc (strlen (repos) + strlen (file)
- + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
- (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
- if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
- {
- rcs = RCS_parsercsfile_i(fp, rcsfile);
- if (rcs != NULL)
- rcs->flags |= VALID;
-
- retval = rcs;
- goto out;
- }
- else if (! existence_error (errno))
+ if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL)
{
- error (0, errno, "cannot open %s", rcsfile);
- retval = NULL;
- goto out;
+ /* Handle the error cases */
}
-
- (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
- if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
+ else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
{
rcs = RCS_parsercsfile_i(fp, rcsfile);
if (rcs != NULL)
- {
- rcs->flags |= INATTIC;
+ {
rcs->flags |= VALID;
+ if ( inattic )
+ rcs->flags |= INATTIC;
}
+ free ( rcsfile );
retval = rcs;
- goto out;
}
else if (! existence_error (errno))
{
+ free ( rcsfile );
error (0, errno, "cannot open %s", rcsfile);
- retval = NULL;
- goto out;
}
-#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
- else if (ign_case)
- {
- int status;
- char *found_path;
-
- /* The client might be asking for a file which we do have
- (which the client doesn't know about), but for which the
- filename case differs. We only consider this case if the
- regular CVS_FOPENs fail, because fopen_case is such an
- expensive call. */
- (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
- status = fopen_case (rcsfile, "rb", &fp, &found_path);
- if (status == 0)
- {
- rcs = RCS_parsercsfile_i (fp, rcsfile);
- if (rcs != NULL)
- rcs->flags |= VALID;
-
- free (rcs->path);
- rcs->path = found_path;
- retval = rcs;
- goto out;
- }
- else if (! existence_error (status))
- {
- error (0, status, "cannot open %s", rcsfile);
- retval = NULL;
- goto out;
- }
-
- (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
- status = fopen_case (rcsfile, "rb", &fp, &found_path);
- if (status == 0)
- {
- rcs = RCS_parsercsfile_i (fp, rcsfile);
- if (rcs != NULL)
- {
- rcs->flags |= INATTIC;
- rcs->flags |= VALID;
- }
-
- free (rcs->path);
- rcs->path = found_path;
- retval = rcs;
- goto out;
- }
- else if (! existence_error (status))
- {
- error (0, status, "cannot open %s", rcsfile);
- retval = NULL;
- goto out;
- }
- }
-#endif
- retval = NULL;
-
- out:
- free (rcsfile);
return retval;
}
@@ -312,7 +314,7 @@ RCS_parse (file, repos)
*/
RCSNode *
RCS_parsercsfile (rcsfile)
- char *rcsfile;
+ const char *rcsfile;
{
FILE *fp;
RCSNode *rcs;
@@ -334,6 +336,7 @@ RCS_parsercsfile (rcsfile)
}
+
/*
*/
static RCSNode *
@@ -347,7 +350,7 @@ RCS_parsercsfile_i (fp, rcsfile)
/* make a node */
rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
- memset ((char *) rdata, 0, sizeof (RCSNode));
+ memset ((char *)rdata, 0, sizeof (RCSNode));
rdata->refcount = 1;
rdata->path = xstrdup (rcsfile);
@@ -365,7 +368,7 @@ RCS_parsercsfile_i (fp, rcsfile)
goto l_error;
if (STREQ (RCSHEAD, key) && value != NULL)
- rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
+ rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
if (! rcsbuf_getkey (&rcsbuf, &key, &value))
goto l_error;
@@ -376,7 +379,7 @@ RCS_parsercsfile_i (fp, rcsfile)
{
char *cp;
- rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
+ rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
if ((numdots (rdata->branch) & 1) != 0)
{
/* turn it into a branch if it's a revision */
@@ -394,12 +397,12 @@ RCS_parsercsfile_i (fp, rcsfile)
if (STREQ (RCSEXPAND, key))
{
rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
- (size_t *) NULL);
+ (size_t *)NULL);
break;
}
for (cp = key;
- (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
cp++)
/* do nothing */ ;
if (*cp == '\0')
@@ -424,10 +427,11 @@ l_error:
rcsbuf_close (&rcsbuf);
freercsnode (&rdata);
fclose (fp);
- return (NULL);
+ return NULL;
}
+
/* Do the real work of parsing an RCS file.
On error, die with a fatal error; if it returns at all it was successful.
@@ -580,7 +584,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
q = getnode ();
q->type = RCSVERS;
q->delproc = rcsvers_delproc;
- q->data = (char *) vnode;
+ q->data = vnode;
q->key = vnode->version;
/* add the nodes to the list */
@@ -632,7 +636,7 @@ RCS_setattic (rcs, toattic)
int toattic;
{
char *newpath;
- char *p;
+ const char *p;
char *q;
/* Some systems aren't going to let us rename an open file. */
@@ -741,7 +745,7 @@ RCS_fully_parse (rcs)
/* Rather than try to keep track of how much information we
have read, just read to the end of the file. */
- if (! rcsbuf_getrevnum (&rcsbuf, &key))
+ if (!rcsbuf_getrevnum (&rcsbuf, &key))
break;
vers = findnode (rcs->versions, key);
@@ -750,11 +754,11 @@ RCS_fully_parse (rcs)
"mismatch in rcs file %s between deltas and deltatexts (%s)",
rcs->path, key);
- vnode = (RCSVers *) vers->data;
+ vnode = vers->data;
while (rcsbuf_getkey (&rcsbuf, &key, &value))
{
- if (! STREQ (key, "text"))
+ if (!STREQ (key, "text"))
{
Node *kv;
@@ -764,7 +768,7 @@ RCS_fully_parse (rcs)
kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
kv->key = xstrdup (key);
kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
- (size_t *) NULL);
+ (size_t *)NULL);
if (addnode (vnode->other, kv) != 0)
{
error (0, 0,
@@ -777,7 +781,7 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
continue;
}
- if (! STREQ (vnode->version, rcs->head))
+ if (!STREQ (vnode->version, rcs->head))
{
unsigned long add, del;
char buf[50];
@@ -876,6 +880,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
rcsbuf_cache (rcs, &rcsbuf);
}
+
+
/*
* freercsnode - free up the info for an RCSNode
*/
@@ -969,7 +975,7 @@ static void
rcsvers_delproc (p)
Node *p;
{
- free_rcsvers_contents ((RCSVers *) p->data);
+ free_rcsvers_contents (p->data);
}
/* These functions retrieve keys and values from an RCS file using a
@@ -2187,8 +2193,8 @@ do_branches (list, val)
char *
RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
RCSNode *rcs;
- char *tag;
- char *date;
+ const char *tag;
+ const char *date;
int force_tag_match;
int *simple_tag;
{
@@ -2221,14 +2227,16 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
return (rev);
}
else if (tag)
- return (RCS_gettag (rcs, tag, force_tag_match, simple_tag));
+ return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
else if (date)
- return (RCS_getdate (rcs, date, force_tag_match));
+ return RCS_getdate (rcs, date, force_tag_match);
else
- return (RCS_head (rcs));
+ return RCS_head (rcs);
}
+
+
/*
* Get existing revision number corresponding to tag or revision.
* Similar to RCS_gettag but less interpretation imposed.
@@ -2334,12 +2342,11 @@ RCS_tag2rev (rcs, tag)
char *
RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
RCSNode *rcs;
- char *symtag;
+ const char *symtag;
int force_tag_match;
int *simple_tag;
{
- char *tag = symtag;
- int tag_allocated = 0;
+ char *tag;
if (simple_tag != NULL)
*simple_tag = 0;
@@ -2351,28 +2358,27 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
if (rcs->flags & PARTIAL)
RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
- /* If tag is "HEAD", special case to get head RCS revision */
- if (tag && STREQ (tag, TAG_HEAD))
+ /* If symtag is "HEAD", special case to get head RCS revision */
+ if (symtag && STREQ (symtag, TAG_HEAD))
#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
return ((char *) NULL); /* head request for removed file */
else
#endif
- return (RCS_head (rcs));
+ return RCS_head (rcs);
- if (!isdigit ((unsigned char) tag[0]))
+ if (!isdigit ((unsigned char) symtag[0]))
{
char *version;
/* If we got a symbolic tag, resolve it to a numeric */
- version = translate_symtag (rcs, tag);
+ version = translate_symtag (rcs, symtag);
if (version != NULL)
{
int dots;
char *magic, *branch, *cp;
tag = version;
- tag_allocated = 1;
/*
* If this is a magic revision, we turn it into either its
@@ -2400,9 +2406,9 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
if (branch != NULL)
{
free (tag);
- return (branch);
+ return branch;
}
- return (tag);
+ return tag;
}
free (magic);
}
@@ -2411,11 +2417,15 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
{
/* The tag wasn't there, so return the head or NULL */
if (force_tag_match)
- return (NULL);
+ return NULL;
else
- return (RCS_head (rcs));
+ return RCS_head (rcs);
}
}
+ else
+ tag = xstrdup (symtag);
+
+ /* tag is always allocated and numeric now. */
/*
* numeric tag processing:
@@ -2433,8 +2443,7 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
/* we have a branch tag, so we need to walk the branch */
branch = RCS_getbranch (rcs, tag, force_tag_match);
- if (tag_allocated)
- free (tag);
+ free (tag);
return branch;
}
else
@@ -2454,19 +2463,16 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
without calling co? */
if (simple_tag != NULL)
*simple_tag = 1;
- if (! tag_allocated)
- tag = xstrdup (tag);
- return (tag);
+ return tag;
}
else
{
/* The revision wasn't there, so return the head or NULL */
- if (tag_allocated)
- free (tag);
+ free (tag);
if (force_tag_match)
- return (NULL);
+ return NULL;
else
- return (RCS_head (rcs));
+ return RCS_head (rcs);
}
}
}
@@ -2691,7 +2697,7 @@ RCS_whatbranch (rcs, rev)
char *
RCS_getbranch (rcs, tag, force_tag_match)
RCSNode *rcs;
- char *tag;
+ const char *tag;
int force_tag_match;
{
Node *p, *head;
@@ -2728,7 +2734,7 @@ RCS_getbranch (rcs, tag, force_tag_match)
else
return (RCS_head (rcs));
}
- vn = (RCSVers *) p->data;
+ vn = p->data;
cp = vn->next;
}
free (xtag);
@@ -2761,7 +2767,7 @@ RCS_getbranch (rcs, tag, force_tag_match)
}
/* find the first element of the branch we are looking for */
- vn = (RCSVers *) p->data;
+ vn = p->data;
if (vn->branches == NULL)
return (NULL);
xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
@@ -2795,7 +2801,7 @@ RCS_getbranch (rcs, tag, force_tag_match)
else
return (RCS_head (rcs));
}
- vn = (RCSVers *) p->data;
+ vn = p->data;
nextvers = vn->next;
} while (nextvers != NULL);
@@ -2886,7 +2892,7 @@ RCS_getbranchpoint (rcs, target)
error (0, 0, "%s: can't find branch point %s", rcs->path, target);
return NULL;
}
- rev = (RCSVers *) vp->data;
+ rev = vp->data;
*bp++ = '.';
while (*bp && *bp != '.')
@@ -2945,7 +2951,7 @@ RCS_head (rcs)
char *
RCS_getdate (rcs, date, force_tag_match)
RCSNode *rcs;
- char *date;
+ const char *date;
int force_tag_match;
{
char *cur_rev = NULL;
@@ -2979,7 +2985,7 @@ RCS_getdate (rcs, date, force_tag_match)
while (p != NULL)
{
/* if the date of this one is before date, take it */
- vers = (RCSVers *) p->data;
+ vers = p->data;
if (RCS_datecmp (vers->date, date) <= 0)
{
cur_rev = vers->version;
@@ -3017,7 +3023,7 @@ RCS_getdate (rcs, date, force_tag_match)
{
char *date_1_1 = vers->date;
- vers = (RCSVers *) p->data;
+ vers = p->data;
if (RCS_datecmp (vers->date, date_1_1) != 0)
return xstrdup ("1.1");
}
@@ -3036,11 +3042,13 @@ RCS_getdate (rcs, date, force_tag_match)
if (!force_tag_match ||
(vers != NULL && RCS_datecmp (vers->date, date) <= 0))
- return (xstrdup (vers->version));
+ return xstrdup (vers->version);
else
- return (NULL);
+ return NULL;
}
+
+
/*
* Look up the last element on a branch that was put in before the specified
* date (return the rev or NULL)
@@ -3048,8 +3056,8 @@ RCS_getdate (rcs, date, force_tag_match)
static char *
RCS_getdatebranch (rcs, date, branch)
RCSNode *rcs;
- char *date;
- char *branch;
+ const char *date;
+ const char *branch;
{
char *cur_rev = NULL;
char *cp;
@@ -3076,7 +3084,7 @@ RCS_getdatebranch (rcs, date, branch)
free (xrev);
if (p == NULL)
return (NULL);
- vers = (RCSVers *) p->data;
+ vers = p->data;
/* Tentatively use this revision, if it is early enough. */
if (RCS_datecmp (vers->date, date) <= 0)
@@ -3109,7 +3117,7 @@ RCS_getdatebranch (rcs, date, branch)
/* walk the next pointers until you find the end, or the date is too late */
while (p != NULL)
{
- vers = (RCSVers *) p->data;
+ vers = p->data;
if (RCS_datecmp (vers->date, date) <= 0)
cur_rev = vers->version;
else
@@ -3126,19 +3134,23 @@ RCS_getdatebranch (rcs, date, branch)
return xstrdup (cur_rev);
}
+
+
/*
* Compare two dates in RCS format. Beware the change in format on January 1,
* 2000, when years go from 2-digit to full format.
*/
int
RCS_datecmp (date1, date2)
- char *date1, *date2;
+ const char *date1, *date2;
{
int length_diff = strlen (date1) - strlen (date2);
- return (length_diff ? length_diff : strcmp (date1, date2));
+ return length_diff ? length_diff : strcmp (date1, date2);
}
+
+
/* Look up revision REV in RCS and return the date specified for the
revision minus FUDGE seconds (FUDGE will generally be one, so that the
logically previous revision will be found later, or zero, if we want
@@ -3153,7 +3165,7 @@ RCS_datecmp (date1, date2)
time_t
RCS_getrevtime (rcs, rev, date, fudge)
RCSNode *rcs;
- char *rev;
+ const char *rev;
char *date;
int fudge;
{
@@ -3173,26 +3185,29 @@ RCS_getrevtime (rcs, rev, date, fudge)
p = findnode (rcs->versions, rev);
if (p == NULL)
return (-1);
- vers = (RCSVers *) p->data;
+ vers = p->data;
/* split up the date */
- ftm = &xtm;
- (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
- &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
- &ftm->tm_sec);
+ if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
+ &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
+ error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path,
+ rev, vers->date);
/* If the year is from 1900 to 1999, RCS files contain only two
digits, and sscanf gives us a year from 0-99. If the year is
2000+, RCS files contain all four digits and we subtract 1900,
because the tm_year field should contain years since 1900. */
- if (ftm->tm_year > 1900)
- ftm->tm_year -= 1900;
+ if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
+ error (0, 0, "%s: non-standard date format for revision %s (%s)",
+ rcs->path, rev, vers->date);
+ if (xtm.tm_year >= 1900)
+ xtm.tm_year -= 1900;
/* put the date in a form getdate can grok */
- (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon,
- ftm->tm_mday, ftm->tm_year + 1900, ftm->tm_hour,
- ftm->tm_min, ftm->tm_sec);
+ (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon,
+ xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour,
+ xtm.tm_min, xtm.tm_sec);
/* turn it into seconds since the epoch */
revdate = get_date (tdate, (struct timeb *) NULL);
@@ -3209,7 +3224,7 @@ RCS_getrevtime (rcs, rev, date, fudge)
ftm->tm_min, ftm->tm_sec);
}
}
- return (revdate);
+ return revdate;
}
List *
@@ -3444,7 +3459,7 @@ RCS_isdead (rcs, tag)
if (p == NULL)
return (0);
- version = (RCSVers *) p->data;
+ version = p->data;
return (version->dead);
}
@@ -3467,7 +3482,7 @@ RCS_getexpand (rcs)
void
RCS_setexpand (rcs, expand)
RCSNode *rcs;
- char *expand;
+ const char *expand;
{
/* Since RCS_parsercsfile_i now reads expand, don't need to worry
about RCS_reparsercsfile. */
@@ -3749,7 +3764,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
case KEYWORD_ID:
case KEYWORD_LOCALID:
{
- char *path;
+ const char *path;
int free_path;
char *date;
char *old_path;
@@ -3781,7 +3796,10 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
locker != NULL ? " " : "",
locker != NULL ? locker : "");
if (free_path)
- free (path);
+ /* If free_path is set then we know we allocated path
+ * and we can discard the const.
+ */
+ free ((char *)path);
if (old_path)
free (old_path);
free (date);
@@ -4060,6 +4078,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
}
}
+
+
/* Check out a revision from an RCS file.
If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
@@ -4099,14 +4119,14 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
int
RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
- RCSNode *rcs;
- char *workfile;
- char *rev;
- char *nametag;
- char *options;
- char *sout;
- RCSCHECKOUTPROC pfn;
- void *callerdat;
+ RCSNode *rcs;
+ const char *workfile;
+ const char *rev;
+ const char *nametag;
+ const char *options;
+ const char *sout;
+ RCSCHECKOUTPROC pfn;
+ void *callerdat;
{
int free_rev = 0;
enum kflag expand;
@@ -4133,7 +4153,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (trace)
{
- (void) fprintf (stderr, "%s-> checkout (%s, %s, %s, %s)\n",
+ (void) fprintf (stderr, "%s-> RCS_checkout (%s, %s, %s, %s, %s)\n",
#ifdef SERVER_SUPPORT
server_active ? "S" : " ",
#else
@@ -4141,6 +4161,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
#endif
rcs->path,
rev != NULL ? rev : "",
+ nametag != NULL ? nametag : "",
options != NULL ? options : "",
(pfn != NULL ? "(function)"
: (workfile != NULL
@@ -4195,7 +4216,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
{
error (0, 0, "internal error: cannot find head text");
if (free_rev)
- free (rev);
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
return 1;
}
@@ -4281,7 +4305,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (vp == NULL)
error (1, 0, "internal error: no revision information for %s",
rev == NULL ? rcs->head : rev);
- vers = (RCSVers *) vp->data;
+ vers = vp->data;
/* First we look for symlinks, which are simplest to handle. */
info = findnode (vers->other_delta, "symlink");
@@ -4306,11 +4330,14 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
error (1, errno, "cannot remove %s", dest);
if (symlink (info->data, dest) < 0)
error (1, errno, "cannot create symbolic link from %s to %s",
- dest, info->data);
+ dest, (char *)info->data);
if (free_value)
free (value);
if (free_rev)
- free (rev);
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
return 0;
}
@@ -4351,8 +4378,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (uptodate_link != NULL)
{
- struct hardlink_info *hlinfo =
- (struct hardlink_info *) uptodate_link->data;
+ struct hardlink_info *hlinfo = uptodate_link->data;
if (link (uptodate_link->key, workfile) < 0)
error (1, errno, "cannot link %s to %s",
@@ -4361,7 +4387,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (free_value)
free (value);
if (free_rev)
- free (rev);
+ /* It's okay to discard the const when free_rev is set,
+ * because we know we allocated it in this function.
+ */
+ free ((char *)rev);
return 0;
}
}
@@ -4394,7 +4423,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (sscanf (info->data, "%15s %lu",
devtype, &devnum_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
- workfile, vers->version, info->data);
+ workfile, vers->version, (char *)info->data);
devnum = devnum_long;
if (STREQ (devtype, "character"))
special_file = S_IFCHR;
@@ -4402,10 +4431,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
special_file = S_IFBLK;
else
error (0, 0, "%s is a special file of unsupported type `%s'",
- workfile, info->data);
+ workfile, (char *)info->data);
}
}
-#endif
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
if (expand != KFLAG_O && expand != KFLAG_B)
{
@@ -4420,7 +4449,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
rev == NULL ? rcs->head : rev);
}
- expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen,
+ expand_keywords (rcs, vp->data, nametag, log, loglen,
expand, value, len, &newvalue, &len);
if (newvalue != value)
@@ -4433,7 +4462,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
}
if (free_rev)
- free (rev);
+ /* It's okay to discard the const when free_rev is set, because
+ * we know we allocated it in this function.
+ */
+ free ((char *)rev);
if (log != NULL)
{
@@ -4703,7 +4735,7 @@ RCS_findlock_or_tip (rcs)
lock->key);
return NULL;
}
- return (RCSVers *) p->data;
+ return p->data;
}
/* No existing lock. The RCS rule is that this is an error unless
@@ -4718,7 +4750,7 @@ RCS_findlock_or_tip (rcs)
that in other ways if at all anyway (e.g. rcslock.pl). */
p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
- return (RCSVers *) p->data;
+ return p->data;
}
/* Revision number string, R, must contain a `.'.
@@ -4849,7 +4881,7 @@ RCS_addbranch (rcs, branch)
return NULL;
}
free (branchpoint);
- branchnode = (RCSVers *) nodep->data;
+ branchnode = nodep->data;
/* If BRANCH was a full branch number, make sure it is higher than MAX. */
if ((numdots (branch) & 1) == 1)
@@ -4949,24 +4981,24 @@ RCS_addbranch (rcs, branch)
or zero for success. */
int
-RCS_checkin (rcs, workfile, message, rev, flags)
+RCS_checkin (rcs, workfile_in, message, rev, flags)
RCSNode *rcs;
- char *workfile;
- char *message;
- char *rev;
+ const char *workfile_in;
+ const char *message;
+ const char *rev;
int flags;
{
RCSVers *delta, *commitpt;
Deltatext *dtext;
Node *nodep;
- char *tmpfile, *changefile, *chtext;
+ char *tmpfile, *changefile;
char *diffopts;
size_t bufsize;
- int buflen, chtextlen;
- int status, checkin_quiet, allocated_workfile;
+ int status, checkin_quiet;
struct tm *ftm;
time_t modtime;
int adding_branch = 0;
+ char *workfile = xstrdup (workfile_in);
#ifdef PRESERVE_PERMISSIONS_SUPPORT
struct stat sb;
#endif
@@ -4978,7 +5010,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
/* Get basename of working file. Is there a library function to
do this? I couldn't find one. -twp */
- allocated_workfile = 0;
if (workfile == NULL)
{
char *p;
@@ -4987,7 +5018,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
p = workfile + (strlen (workfile) - extlen);
assert (strncmp (p, RCSEXT, extlen) == 0);
*p = '\0';
- allocated_workfile = 1;
}
/* If the filename is a symbolic link, follow it and replace it
@@ -5144,7 +5174,7 @@ workfile);
nodep = getnode();
nodep->type = RCSVERS;
nodep->delproc = rcsvers_delproc;
- nodep->data = (char *) delta;
+ nodep->data = delta;
nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
@@ -5324,7 +5354,7 @@ workfile);
}
nodep = findnode (rcs->versions, tip);
- commitpt = (RCSVers *) nodep->data;
+ commitpt = nodep->data;
free (branch);
free (newrev);
@@ -5353,7 +5383,7 @@ workfile);
{
error (0, 0, "%s: revision %s locked by %s",
rcs->path,
- nodep->key, nodep->data);
+ nodep->key, (char *)nodep->data);
status = 1;
goto checkin_done;
}
@@ -5383,9 +5413,7 @@ workfile);
"could not check out revision %s of `%s'",
commitpt->version, rcs->path);
- bufsize = buflen = 0;
- chtext = NULL;
- chtextlen = 0;
+ bufsize = 0;
changefile = cvs_temp_name();
/* Diff options should include --binary if the RCS file has -kb set
@@ -5519,7 +5547,7 @@ workfile);
nodep = getnode();
nodep->type = RCSVERS;
nodep->delproc = rcsvers_delproc;
- nodep->data = (char *) delta;
+ nodep->data = delta;
nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
@@ -5552,8 +5580,7 @@ workfile);
cvs_output ("done\n", 5);
checkin_done:
- if (allocated_workfile)
- free (workfile);
+ free (workfile);
if (commitpt != NULL && commitpt->text != NULL)
{
@@ -5568,8 +5595,9 @@ workfile);
return status;
}
-/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
+
+/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
struct cmp_file_data
{
const char *filename;
@@ -5577,22 +5605,21 @@ struct cmp_file_data
int different;
};
-/* Compare the contents of revision REV of RCS file RCS with the
- contents of the file FILENAME. OPTIONS is a string for the keyword
+/* Compare the contents of revision REV1 of RCS file RCS with the
+ contents of REV2 if given, otherwise, compare with the contents of
+ the file FILENAME. OPTIONS is a string for the keyword
expansion options. Return 0 if the contents of the revision are
the same as the contents of the file, 1 if they are different. */
-
int
-RCS_cmp_file (rcs, rev, options, filename)
+RCS_cmp_file (rcs, rev1, rev1_cache, rev2, options, filename)
RCSNode *rcs;
- char *rev;
- char *options;
+ const char *rev1;
+ char **rev1_cache;
+ const char *rev2;
+ const char *options;
const char *filename;
{
int binary;
- FILE *fp;
- struct cmp_file_data data;
- int retcode;
if (options != NULL && options[0] != '\0')
binary = STREQ (options, "-kb");
@@ -5620,6 +5647,7 @@ RCS_cmp_file (rcs, rev, options, filename)
if (preserve_perms)
{
char *tmp;
+ int retcode;
tmp = cvs_temp_name();
retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
@@ -5635,39 +5663,67 @@ RCS_cmp_file (rcs, rev, options, filename)
else
#endif
{
- fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
+ FILE *fp;
+ struct cmp_file_data data;
+ const char *use_file1;
+ char *tmpfile = NULL;
+
+ if (rev2 != NULL)
+ {
+ /* Open & cache rev1 */
+ tmpfile = cvs_temp_name();
+ if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
+ (RCSCHECKOUTPROC)0, NULL))
+ error (1, errno,
+ "cannot check out revision %s of %s",
+ rev1, rcs->path);
+ use_file1 = tmpfile;
+ if (rev1_cache != NULL)
+ *rev1_cache = tmpfile;
+ }
+ else
+ use_file1 = filename;
+
+ fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
if (fp == NULL)
/* FIXME-update-dir: should include update_dir in message. */
- error (1, errno, "cannot open file %s for comparing", filename);
+ error (1, errno, "cannot open file %s for comparing", use_file1);
- data.filename = filename;
+ data.filename = use_file1;
data.fp = fp;
data.different = 0;
- retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
- options, RUN_TTY, cmp_file_buffer,
- (void *) &data);
+ if (RCS_checkout (rcs, (char *)NULL, rev2 ? rev2 : rev1,
+ (char *)NULL, options, RUN_TTY, cmp_file_buffer,
+ (void *)&data ))
+ error (1, errno,
+ "cannot check out revision %s of %s",
+ rev2 ? rev2 : rev1, rcs->path);
/* If we have not yet found a difference, make sure that we are at
the end of the file. */
- if (! data.different)
+ if (!data.different)
{
if (getc (fp) != EOF)
data.different = 1;
}
fclose (fp);
+ if (rev1_cache == NULL && tmpfile)
+ {
+ if (CVS_UNLINK (tmpfile ) < 0)
+ error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
+ }
- if (retcode != 0)
- return 1;
-
return data.different;
}
}
+
+
/* This is a subroutine of RCS_cmp_file. It is passed to
RCS_checkout. */
-
#define CMP_BUF_SIZE (8 * 1024)
static void
@@ -5676,7 +5732,7 @@ cmp_file_buffer (callerdat, buffer, len)
const char *buffer;
size_t len;
{
- struct cmp_file_data *data = (struct cmp_file_data *) callerdat;
+ struct cmp_file_data *data = (struct cmp_file_data *)callerdat;
char *filebuf;
/* If we've already found a difference, we don't need to check
@@ -5715,6 +5771,8 @@ cmp_file_buffer (callerdat, buffer, len)
free (filebuf);
}
+
+
/* For RCS file RCS, make symbolic tag TAG point to revision REV.
This validates that TAG is OK for a user to use. Return value is
-1 for error (and errno is set to indicate the error), positive for
@@ -5843,7 +5901,7 @@ RCS_setbranch (rcs, rev)
int
RCS_lock (rcs, rev, lock_quiet)
RCSNode *rcs;
- char *rev;
+ const char *rev;
int lock_quiet;
{
List *locks;
@@ -5907,7 +5965,7 @@ RCS_lock (rcs, rev, lock_quiet)
}
delnode (p);
#else
- error (1, 0, "Revision %s is already locked by %s", xrev, p->data);
+ error (1, 0, "Revision %s is already locked by %s", xrev, (char *)p->data);
#endif
}
@@ -6023,7 +6081,7 @@ RCS_unlock (rcs, rev, unlock_quiet)
char *repos, *workfile;
if (!unlock_quiet)
error (0, 0, "\
-%s: revision %s locked by %s; breaking lock", rcs->path, xrev, lock->data);
+%s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data);
repos = xstrdup (rcs->path);
workfile = strrchr (repos, '/');
*workfile++ = '\0';
@@ -6328,10 +6386,10 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
{
/* Walk deltas from BRANCHPOINT on, looking for REV1. */
nodep = findnode (rcs->versions, branchpoint);
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
while (revp->next != NULL && ! STREQ (revp->next, rev1))
{
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
nodep = findnode (rcs->versions, revp->next);
}
if (revp->next == NULL)
@@ -6375,7 +6433,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
while (!found && next != NULL)
{
nodep = findnode (rcs->versions, next);
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
if (rev2 != NULL)
found = STREQ (revp->version, rev2);
@@ -6479,7 +6537,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
char *diffbuf;
size_t bufsize, len;
-#if defined (__CYGWIN32__) || defined (_WIN32)
+#if defined (WOE32) && !defined (__CYGWIN32__)
/* FIXME: This is an awful kludge, but at least until I have
time to work on it a little more and test it, I'd rather
give a fatal error than corrupt the file. I think that we
@@ -6492,7 +6550,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
error (1, 0,
"admin -o not implemented yet for binary on this system");
}
-#endif
+#endif /* WOE32 */
afterfile = cvs_temp_name();
status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
@@ -6547,7 +6605,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
/* Save the new change text in after's delta node. */
nodep = findnode (rcs->versions, after);
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
assert (revp->text == NULL);
@@ -6575,7 +6633,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
next = revp->next)
{
nodep = findnode (rcs->versions, next);
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
revp->outdated = 1;
}
@@ -6599,7 +6657,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
else if (STREQ (rev1, branchpoint))
{
nodep = findnode (rcs->versions, before);
- revp = (RCSVers *) nodep->data;
+ revp = nodep->data;
nodep = revp->branches->list->next;
while (nodep != revp->branches->list &&
! STREQ (nodep->key, rev1))
@@ -6616,7 +6674,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
else
{
nodep = findnode (rcs->versions, before);
- beforep = (RCSVers *) nodep->data;
+ beforep = nodep->data;
free (beforep->next);
beforep->next = xstrdup (after);
}
@@ -7173,7 +7231,7 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
RCSNode *rcs;
FILE *fp;
struct rcsbuffer *rcsbuf;
- char *version;
+ const char *version;
enum rcs_delta_op op;
char **text;
size_t *len;
@@ -7251,7 +7309,7 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
/* Stash the previous version. */
prev_vers = vers;
- vers = (RCSVers *) node->data;
+ vers = node->data;
next = vers->next;
/* Compare key and trunkversion now, because key points to
@@ -7820,7 +7878,7 @@ putlock_proc (symnode, fp)
Node *symnode;
void *fp;
{
- return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->data, symnode->key);
+ return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
}
static int
@@ -8016,7 +8074,7 @@ RCS_putdtree (rcs, rev, fp)
rcs->path);
}
- versp = (RCSVers *) p->data;
+ versp = p->data;
/* Print the delta node and recurse on its `next' node. This prints
the trunk. If there are any branches printed on this revision,
@@ -8133,7 +8191,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
}
np = findnode (rcs->versions, dtext->version);
- dadmin = (RCSVers *) np->data;
+ dadmin = np->data;
/* If this revision has been outdated, just skip it. */
if (dadmin->outdated)
@@ -8245,9 +8303,7 @@ count_delta_actions (np, ignore)
Node *np;
void *ignore;
{
- RCSVers *dadmin;
-
- dadmin = (RCSVers *) np->data;
+ RCSVers *dadmin = np->data;
if (dadmin->outdated)
return 1;
@@ -8441,10 +8497,10 @@ rcs_internal_unlockfile (fp, rcsfile)
static char *
rcs_lockfilename (rcsfile)
- char *rcsfile;
+ const char *rcsfile;
{
char *lockfile, *lockp;
- char *rcsbase, *rcsp, *rcsend;
+ const char *rcsbase, *rcsp, *rcsend;
int rcslen;
/* Create the lockfile name. */
@@ -8552,8 +8608,8 @@ RCS_abandon (rcs)
*/
char *
make_file_label (path, rev, rcs)
- char *path;
- char *rev;
+ const char *path;
+ const char *rev;
RCSNode *rcs;
{
char datebuf[MAXDATELEN + 1];
@@ -8576,15 +8632,17 @@ make_file_label (path, rev, rcs)
else
{
struct stat sb;
- struct tm *wm = NULL;
+ struct tm *wm;
if (strcmp(DEVNULL, path))
{
- char *file = last_component (path);
+ const char *file = last_component (path);
if (CVS_STAT (file, &sb) < 0)
- error (0, 1, "could not get info for `%s'", path);
- else
- wm = gmtime (&sb.st_mtime);
+ /* Assume that if the stat fails,then the later read for the
+ * diff will too.
+ */
+ error (1, errno, "could not get info for `%s'", path);
+ wm = gmtime (&sb.st_mtime);
}
else
{
@@ -8592,11 +8650,8 @@ make_file_label (path, rev, rcs)
wm = gmtime(&t);
}
- if (wm)
- {
- (void) tm_to_internet (datebuf, wm);
- (void) sprintf (label, "-L%s\t%s", path, datebuf);
- }
+ (void) tm_to_internet (datebuf, wm);
+ (void) sprintf (label, "-L%s\t%s", path, datebuf);
}
return label;
}
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index e44a45c..a2a30f7 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -188,47 +188,51 @@ enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
* exported interfaces
*/
RCSNode *RCS_parse PROTO((const char *file, const char *repos));
-RCSNode *RCS_parsercsfile PROTO((char *rcsfile));
+RCSNode *RCS_parsercsfile PROTO((const char *rcsfile));
void RCS_fully_parse PROTO((RCSNode *));
void RCS_reparsercsfile PROTO((RCSNode *, FILE **, struct rcsbuffer *));
extern int RCS_setattic PROTO ((RCSNode *, int));
char *RCS_check_kflag PROTO((const char *arg));
-char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
-char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match,
- int *simple_tag));
+char *RCS_getdate PROTO((RCSNode * rcs, const char *date,
+ int force_tag_match));
+char *RCS_gettag PROTO((RCSNode * rcs, const char *symtag, int force_tag_match,
+ int *simple_tag));
int RCS_exist_rev PROTO((RCSNode *rcs, char *rev));
int RCS_exist_tag PROTO((RCSNode *rcs, char *tag));
char *RCS_tag2rev PROTO((RCSNode *rcs, char *tag));
-char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date,
- int force_tag_match, int *simple_tag));
+char *RCS_getversion PROTO((RCSNode * rcs, const char *tag, const char *date,
+ int force_tag_match, int *simple_tag));
char *RCS_magicrev PROTO((RCSNode *rcs, char *rev));
int RCS_isbranch PROTO((RCSNode *rcs, const char *rev));
int RCS_nodeisbranch PROTO((RCSNode *rcs, const char *tag));
char *RCS_whatbranch PROTO((RCSNode *rcs, const char *tag));
char *RCS_head PROTO((RCSNode * rcs));
-int RCS_datecmp PROTO((char *date1, char *date2));
-time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
+int RCS_datecmp PROTO((const char *date1, const char *date2));
+time_t RCS_getrevtime PROTO((RCSNode * rcs, const char *rev, char *date,
+ int fudge));
List *RCS_symbols PROTO((RCSNode *rcs));
void RCS_check_tag PROTO((const char *tag));
int RCS_valid_rev PROTO ((char *rev));
List *RCS_getlocks PROTO((RCSNode *rcs));
void freercsnode PROTO((RCSNode ** rnodep));
-char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match));
+char *RCS_getbranch PROTO((RCSNode * rcs, const char *tag,
+ int force_tag_match));
char *RCS_branch_head PROTO ((RCSNode *rcs, char *rev));
int RCS_isdead PROTO((RCSNode *, const char *));
char *RCS_getexpand PROTO ((RCSNode *));
-void RCS_setexpand PROTO ((RCSNode *, char *));
-int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *,
- RCSCHECKOUTPROC, void *));
-int RCS_checkin PROTO ((RCSNode *rcs, char *workfile, char *message,
- char *rev, int flags));
-int RCS_cmp_file PROTO ((RCSNode *, char *, char *, const char *));
+void RCS_setexpand PROTO ((RCSNode *, const char *));
+int RCS_checkout PROTO ((RCSNode *, const char *, const char *, const char *,
+ const char *, const char *, RCSCHECKOUTPROC, void *));
+int RCS_checkin PROTO ((RCSNode *rcs, const char *workfile,
+ const char *message, const char *rev, int flags));
+int RCS_cmp_file PROTO((RCSNode *, const char *, char **, const char *,
+ const char *, const char *));
int RCS_settag PROTO ((RCSNode *, const char *, const char *));
int RCS_deltag PROTO ((RCSNode *, const char *));
int RCS_setbranch PROTO((RCSNode *, const char *));
-int RCS_lock PROTO ((RCSNode *, char *, int));
+int RCS_lock PROTO ((RCSNode *, const char *, int));
int RCS_unlock PROTO ((RCSNode *, char *, int));
int RCS_delete_revs PROTO ((RCSNode *, char *, char *, int));
void RCS_addaccess PROTO ((RCSNode *, char *));
@@ -239,16 +243,17 @@ 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_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *,
+void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, const char *,
enum rcs_delta_op, char **, size_t *,
char **, size_t *));
void RCS_setincexc PROTO ((const char *arg));
void RCS_setlocalid PROTO ((const char *arg));
-char *make_file_label PROTO ((char *, char *, RCSNode *));
+char *make_file_label PROTO ((const char *, const char *, RCSNode *));
extern int preserve_perms;
/* From import.c. */
-extern int add_rcs_file PROTO ((char *, char *, char *, char *, char *,
- char *, char *, int, char **,
- char *, size_t, FILE *));
+extern int add_rcs_file PROTO ((const char *, const char *, const char *,
+ const char *, const char *, const char *,
+ const char *, int, char **, const char *,
+ size_t, FILE *));
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index 2ce586b..df91ff8 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -53,7 +53,8 @@
On a related note, see the comments at diff_exec, later in this file,
for more on the diff library. */
-static void RCS_output_diff_options PROTO ((char *, char *, char *, char *));
+static void RCS_output_diff_options PROTO ((const char *, const char *,
+ const char *, const char *));
/* Stuff to deal with passing arguments the way libdiff.a wants to deal
@@ -76,7 +77,7 @@ static int call_diff_argc_allocated;
static void call_diff_add_arg PROTO ((const char *));
static void call_diff_setup PROTO ((const char *prog));
-static int call_diff PROTO ((char *out));
+static int call_diff PROTO ((const char *out));
static int call_diff3 PROTO ((char *out));
static void call_diff_write_output PROTO((const char *, size_t));
@@ -206,9 +207,11 @@ static struct diff_callbacks call_diff_file_callbacks =
call_diff_error
};
+
+
static int
call_diff (out)
- char *out;
+ const char *out;
{
if (out == RUN_TTY)
return diff_run (call_diff_argc, call_diff_argv, NULL,
@@ -218,6 +221,8 @@ call_diff (out)
&call_diff_file_callbacks);
}
+
+
static int
call_diff3 (out)
char *out;
@@ -237,11 +242,11 @@ call_diff3 (out)
int
RCS_merge(rcs, path, workfile, options, rev1, rev2)
RCSNode *rcs;
- char *path;
- char *workfile;
- char *options;
- char *rev1;
- char *rev2;
+ const char *path;
+ const char *workfile;
+ const char *options;
+ const char *rev1;
+ const char *rev2;
{
char *xrev1, *xrev2;
char *tmp1, *tmp2;
@@ -310,6 +315,7 @@ RCS_merge(rcs, path, workfile, options, rev1, rev2)
call_diff_arg ("-L");
call_diff_arg (xrev2);
+ call_diff_arg ("--");
call_diff_arg (workfile);
call_diff_arg (tmp1);
call_diff_arg (tmp2);
@@ -378,23 +384,23 @@ RCS_merge(rcs, path, workfile, options, rev1, rev2)
about this--any such features are undocumented in the context of
CVS, and I'm not sure how important to users. */
int
-RCS_exec_rcsdiff (rcsfile, opts, options, rev1, rev2, label1, label2, workfile)
+RCS_exec_rcsdiff(rcsfile, opts, options, rev1, rev1_cache, rev2,
+ label1, label2, workfile )
RCSNode *rcsfile;
- char *opts;
- char *options;
- char *rev1;
- char *rev2;
- char *label1;
- char *label2;
- char *workfile;
+ const char *opts;
+ const char *options;
+ const char *rev1;
+ const char *rev1_cache;
+ const char *rev2;
+ const char *label1;
+ const char *label2;
+ const char *workfile;
{
- char *tmpfile1;
- char *tmpfile2;
- char *use_file2;
+ char *tmpfile1 = NULL;
+ char *tmpfile2 = NULL;
+ const char *use_file1, *use_file2;
int status, retval;
- tmpfile1 = cvs_temp_name ();
- tmpfile2 = NULL;
cvs_output ("\
===================================================================\n\
@@ -411,19 +417,27 @@ RCS file: ", 0);
cvs_output ("retrieving revision ", 0);
cvs_output (rev1, 0);
cvs_output ("\n", 1);
- status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
- (RCSCHECKOUTPROC)0, NULL);
- if (status > 0)
- {
- retval = status;
- goto error_return;
- }
- else if (status < 0)
+
+ if (rev1_cache != NULL)
+ use_file1 = rev1_cache;
+ else
{
- error (0, errno,
- "cannot check out revision %s of %s", rev1, rcsfile->path);
- retval = 1;
- goto error_return;
+ tmpfile1 = cvs_temp_name();
+ status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
+ (RCSCHECKOUTPROC)0, NULL);
+ if (status > 0)
+ {
+ retval = status;
+ goto error_return;
+ }
+ else if (status < 0)
+ {
+ error( 0, errno,
+ "cannot check out revision %s of %s", rev1, rcsfile->path );
+ retval = 1;
+ goto error_return;
+ }
+ use_file1 = tmpfile1;
}
if (rev2 == NULL)
@@ -454,7 +468,7 @@ RCS file: ", 0);
}
RCS_output_diff_options (opts, rev1, rev2, workfile);
- status = diff_exec (tmpfile1, use_file2, label1, label2, opts, RUN_TTY);
+ status = diff_exec( use_file1, use_file2, label1, label2, opts, RUN_TTY );
if (status >= 0)
{
retval = status;
@@ -463,40 +477,41 @@ RCS file: ", 0);
else if (status < 0)
{
error (0, errno,
- "cannot diff %s and %s", tmpfile1, use_file2);
+ "cannot diff %s and %s", use_file1, use_file2);
retval = 1;
goto error_return;
}
error_return:
{
- int save_noexec = noexec;
- noexec = 0;
- if (unlink_file (tmpfile1) < 0)
+ /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
+ * for noexec.
+ */
+ if( tmpfile1 != NULL )
{
- if (!existence_error (errno))
- error (0, errno, "cannot remove temp file %s", tmpfile1);
+ if( CVS_UNLINK( tmpfile1 ) < 0 )
+ {
+ if( !existence_error( errno ) )
+ error( 0, errno, "cannot remove temp file %s", tmpfile1 );
+ }
+ free( tmpfile1 );
}
- noexec = save_noexec;
- }
- free (tmpfile1);
- if (tmpfile2 != NULL)
- {
- int save_noexec = noexec;
- noexec = 0;
- if (unlink_file (tmpfile2) < 0)
+ if( tmpfile2 != NULL )
{
- if (!existence_error (errno))
- error (0, errno, "cannot remove temp file %s", tmpfile2);
+ if( CVS_UNLINK( tmpfile2 ) < 0 )
+ {
+ if( !existence_error( errno ) )
+ error( 0, errno, "cannot remove temp file %s", tmpfile2 );
+ }
+ free (tmpfile2);
}
- noexec = save_noexec;
- free (tmpfile2);
}
return retval;
}
+
/* Show differences between two files. This is the start of a diff library.
Some issues:
@@ -533,12 +548,12 @@ RCS file: ", 0);
int
diff_exec (file1, file2, label1, label2, options, out)
- char *file1;
- char *file2;
- char *label1;
- char *label2;
- char *options;
- char *out;
+ const char *file1;
+ const char *file2;
+ const char *label1;
+ const char *label2;
+ const char *options;
+ const char *out;
{
char *args;
@@ -599,10 +614,10 @@ diff_exec (file1, file2, label1, label2, options, out)
static void
RCS_output_diff_options (opts, rev1, rev2, workfile)
- char *opts;
- char *rev1;
- char *rev2;
- char *workfile;
+ const char *opts;
+ const char *rev1;
+ const char *rev2;
+ const char *workfile;
{
char *tmp;
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index 35ebc64..20a0f9b 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -13,6 +13,7 @@
#include "savecwd.h"
#include "fileattr.h"
#include "edit.h"
+#include <assert.h>
static int do_dir_proc PROTO((Node * p, void *closure));
static int do_file_proc PROTO((Node * p, void *closure));
@@ -36,6 +37,7 @@ struct recursion_frame {
int aflag;
int locktype;
int dosrcs;
+ char *repository; /* Keep track of repository for rtag */
};
static int do_recursion PROTO ((struct recursion_frame *frame));
@@ -68,7 +70,7 @@ struct frame_and_entries {
int
start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
argc, argv, local, which, aflag, locktype,
- update_preload, dosrcs)
+ update_preload, dosrcs, repository_in)
FILEPROC fileproc;
FILESDONEPROC filesdoneproc;
DIRENTPROC direntproc;
@@ -106,6 +108,15 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
int locktype;
char *update_preload;
int dosrcs;
+ /* Keep track of the repository string. This is only for the remote mode,
+ * specifically, r* commands (rtag, rdiff, co, ...) where xgetwd() was
+ * used to locate the repository. Things would break when xgetwd() was
+ * used with a symlinked repository because xgetwd() would return the true
+ * path and in some cases this would cause the path to be printed as other
+ * than the user specified in error messages and in other cases some of
+ * CVS's security assertions would fail.
+ */
+ char *repository_in;
{
int i, err = 0;
#ifdef CLIENT_SUPPORT
@@ -124,6 +135,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
frame.aflag = aflag;
frame.locktype = locktype;
frame.dosrcs = dosrcs;
+ frame.repository = repository_in;
expand_wild (argc, argv, &argc, &argv);
@@ -262,7 +274,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
/* Now break out argv[i] into directory part (DIR) and file part (COMP).
DIR and COMP will each point to a newly malloc'd string. */
dir = xstrdup (argv[i]);
- comp = last_component (dir);
+ /* Its okay to discard the const below - we know we just allocated
+ * dir ourselves.
+ */
+ comp = (char *)last_component (dir);
if (comp == dir)
{
/* no dir component. What we have is an implied "./" */
@@ -503,7 +518,7 @@ do_recursion (frame)
{
int err = 0;
int dodoneproc = 1;
- char *srepository;
+ char *srepository = NULL;
List *entries = NULL;
int locktype;
int process_this_directory = 1;
@@ -614,17 +629,19 @@ do_recursion (frame)
if (frame->which & W_LOCAL)
{
if (isdir (CVSADM))
+ {
repository = Name_Repository ((char *) NULL, update_dir);
+ srepository = repository; /* remember what to free */
+ }
else
repository = NULL;
}
else
{
- repository = xgetwd ();
- if (repository == NULL)
- error (1, errno, "could not get working directory");
+ repository = frame->repository;
+ assert (repository != NULL);
+ assert (strstr (repository, "/./") == NULL);
}
- srepository = repository; /* remember what to free */
fileattr_startdir (repository);
@@ -663,7 +680,10 @@ do_recursion (frame)
repository at this point. Name_Repository will give a
reasonable error message. */
if (repository == NULL)
- repository = Name_Repository ((char *) NULL, update_dir);
+ {
+ Name_Repository ((char *) NULL, update_dir);
+ assert (!"Not reached. Please report this problem to <bug-cvs@gnu.org>");
+ }
/* find the files and fill in entries if appropriate */
if (process_this_directory)
@@ -737,7 +757,10 @@ do_recursion (frame)
err += walklist (filelist, do_file_proc, &frfile);
/* unlock it */
- if (locktype != CVS_LOCK_NONE)
+ if (/* We only lock the repository above when repository is set */
+ repository
+ /* and when asked for a read or write lock. */
+ && locktype != CVS_LOCK_NONE)
Lock_Cleanup ();
/* clean up */
@@ -779,12 +802,14 @@ do_recursion (frame)
if (srepository)
{
free (srepository);
- repository = (char *) NULL;
}
+ repository = (char *) NULL;
- return (err);
+ return err;
}
+
+
/*
* Process each of the files in the list with the callback proc
*/
@@ -796,18 +821,19 @@ do_file_proc (p, closure)
struct frame_and_file *frfile = (struct frame_and_file *)closure;
struct file_info *finfo = frfile->finfo;
int ret;
+ char *tmp;
finfo->file = p->key;
- finfo->fullname = xmalloc (strlen (finfo->file)
+ tmp = xmalloc (strlen (finfo->file)
+ strlen (finfo->update_dir)
+ 2);
- finfo->fullname[0] = '\0';
+ tmp[0] = '\0';
if (finfo->update_dir[0] != '\0')
{
- strcat (finfo->fullname, finfo->update_dir);
- strcat (finfo->fullname, "/");
+ strcat (tmp, finfo->update_dir);
+ strcat (tmp, "/");
}
- strcat (finfo->fullname, finfo->file);
+ strcat (tmp, finfo->file);
if (frfile->frame->dosrcs && repository)
{
@@ -822,27 +848,30 @@ do_file_proc (p, closure)
if (finfo->rcs == NULL
&& !(frfile->frame->which & W_LOCAL))
{
- error (0, 0, "could not read RCS file for %s", finfo->fullname);
- free (finfo->fullname);
+ error (0, 0, "could not read RCS file for %s", tmp);
+ free (tmp);
cvs_flushout ();
return 0;
}
}
else
finfo->rcs = (RCSNode *) NULL;
+ finfo->fullname = tmp;
ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo);
freercsnode(&finfo->rcs);
- free (finfo->fullname);
+ free (tmp);
/* Allow the user to monitor progress with tail -f. Doing this once
per file should be no big deal, but we don't want the performance
hit of flushing on every line like previous versions of CVS. */
cvs_flushout ();
- return (ret);
+ return ret;
}
+
+
/*
* Process each of the directories in the list (recursing as we go)
*/
@@ -1077,7 +1106,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
dirlist = NULL;
/* cd to the sub-directory */
- if ( CVS_CHDIR (dir) < 0)
+ if (CVS_CHDIR (dir) < 0)
error (1, errno, "could not chdir to %s", dir);
/* honor the global SKIP_DIRS (a.k.a. local) */
@@ -1094,7 +1123,30 @@ but CVS uses %s for its own purposes; skipping %s directory",
/* make the recursive call */
xframe = *frame;
xframe.flags = dir_return;
+ /* Keep track of repository, really just for r* commands (rtag, rdiff,
+ * co, ...) to tag_check_valid, since all the other commands use
+ * CVS/Repository to figure it out per directory.
+ */
+ if (repository)
+ {
+ if (strcmp (dir, ".") == 0)
+ xframe.repository = xstrdup (repository);
+ else
+ {
+ xframe.repository = xmalloc (strlen (repository)
+ + strlen (dir)
+ + 2);
+ sprintf (xframe.repository, "%s/%s", repository, dir);
+ }
+ }
+ else
+ xframe.repository = NULL;
err += do_recursion (&xframe);
+ if (xframe.repository)
+ {
+ free (xframe.repository);
+ xframe.repository = NULL;
+ }
/* put the `.' back if necessary */
if (stripped_dot)
@@ -1116,7 +1168,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
free (update_dir);
update_dir = saved_update_dir;
- return (err);
+ return err;
}
/*
@@ -1158,9 +1210,9 @@ addfile (listp, dir, file)
}
n->type = DIRS;
- fl = (List *) n->data;
+ fl = n->data;
addlist (&fl, file);
- n->data = (char *) fl;
+ n->data = fl;
return;
}
@@ -1183,7 +1235,7 @@ unroll_files_proc (p, closure)
return (0);
/* otherwise, call dorecusion for this list of files. */
- filelist = (List *) p->data;
+ filelist = p->data;
p->data = NULL;
save_dirlist = dirlist;
dirlist = NULL;
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index ddc3488..6921522 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -211,7 +211,7 @@ fd_buffer_input (closure, data, need, size, got)
else
{
/* This case is not efficient. Fortunately, I don't think it
- ever actually happens. */
+ ever actually happens. */
nbytes = read (fd->fd, data, need == 0 ? 1 : need);
}
@@ -226,8 +226,8 @@ fd_buffer_input (closure, data, need, size, got)
if (nbytes == 0)
{
/* End of file. This assumes that we are using POSIX or BSD
- style nonblocking I/O. On System V we will get a zero
- return if there is no data, even when not at EOF. */
+ style nonblocking I/O. On System V we will get a zero
+ return if there is no data, even when not at EOF. */
return -1;
}
@@ -267,14 +267,14 @@ fd_buffer_output (closure, data, have, wrote)
&& (nbytes == 0 || blocking_error (errno)))
{
/* A nonblocking write failed to write any data. Just
- return. */
+ return. */
return 0;
}
/* Some sort of error occurred. */
if (nbytes == 0)
- return EIO;
+ return EIO;
return errno;
}
@@ -318,7 +318,7 @@ fd_buffer_block (closure, block)
flags |= O_NONBLOCK;
if (fcntl (fd->fd, F_SETFL, flags) < 0)
- return errno;
+ return errno;
fd->blocking = block;
@@ -332,6 +332,7 @@ fd_buffer_shutdown (buf)
struct buffer *buf;
{
free (buf->closure);
+ buf->closure = NULL;
return 0;
}
@@ -856,12 +857,8 @@ outside_root (repos)
size_t repos_len = strlen (repos);
size_t root_len = strlen (current_parsed_root->directory);
- /* I think isabsolute (repos) should always be true, and that
- any RELATIVE_REPOS stuff should only be in CVS/Repository
- files, not the protocol (for compatibility), but I'm putting
- in the isabsolute check just in case.
-
- This is a good security precaution regardless. -DRP
+ /* isabsolute (repos) should always be true, but
+ this is a good security precaution regardless. -DRP
*/
if (!isabsolute (repos))
{
@@ -1087,7 +1084,7 @@ dirswitch (dir, repos)
&& current_parsed_root->directory != NULL
&& strcmp (current_parsed_root->directory, repos) == 0)
{
- if (fprintf (f, "/.") < 0)
+ if (fprintf (f, "/.") < 0)
{
int save_errno = errno;
if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
@@ -1164,7 +1161,7 @@ serve_directory (arg)
}
else if (status == -2)
{
- pending_error = ENOMEM;
+ pending_error = ENOMEM;
}
else
{
@@ -1303,7 +1300,7 @@ receive_partial_file (size, file)
nwrote = write (file, data, nread);
if (nwrote < 0)
{
- int save_errno = errno;
+ int save_errno = errno;
if (alloc_pending (40))
strcpy (pending_error_text, "E unable to write");
pending_error = save_errno;
@@ -1477,7 +1474,7 @@ serve_modified (arg)
status = buf_read_line (buf_from_net, &mode_text, (int *) NULL);
if (status != 0)
{
- if (status == -2)
+ if (status == -2)
pending_error = ENOMEM;
else
{
@@ -1537,7 +1534,7 @@ serve_modified (arg)
if (error_pending ())
{
- /* Now that we know the size, read and discard the file data. */
+ /* Now that we know the size, read and discard the file data. */
while (size > 0)
{
int status, nread;
@@ -1859,10 +1856,10 @@ server_write_entries ()
if (!error_pending ())
{
/* We open in append mode because we don't want to clobber an
- existing Entries file. If we are checking out a module
- which explicitly lists more than one file in a particular
- directory, then we will wind up calling
- server_write_entries for each such file. */
+ existing Entries file. If we are checking out a module
+ which explicitly lists more than one file in a particular
+ directory, then we will wind up calling
+ server_write_entries for each such file. */
f = CVS_FOPEN (CVSADM_ENT, "a");
if (f == NULL)
{
@@ -2076,9 +2073,9 @@ server_notify ()
{
char *dir = notify_list->dir + strlen (server_temp_dir) + 1;
if (dir[0] == '\0')
- buf_append_char (buf_to_net, '.');
+ buf_append_char (buf_to_net, '.');
else
- buf_output0 (buf_to_net, dir);
+ buf_output0 (buf_to_net, dir);
buf_append_char (buf_to_net, '/');
buf_append_char (buf_to_net, '\n');
}
@@ -2179,8 +2176,12 @@ serve_global_option (arg)
}
switch (arg[1])
{
+ case 'l':
+ error(0, 0, "WARNING: global `-l' option ignored.");
+ break;
case 'n':
noexec = 1;
+ logoff = 1;
break;
case 'q':
quiet = 1;
@@ -2191,9 +2192,6 @@ serve_global_option (arg)
case 'Q':
really_quiet = 1;
break;
- case 'l':
- logoff = 1;
- break;
case 't':
trace = 1;
break;
@@ -2240,10 +2238,10 @@ serve_gssapi_encrypt (arg)
if (cvs_gssapi_wrapping)
{
/* We're already using a gssapi_wrap buffer for stream
- authentication. Flush everything we've output so far, and
- turn on encryption for future data. On the input side, we
- should only have unwrapped as far as the Gssapi-encrypt
- command, so future unwrapping will become encrypted. */
+ authentication. Flush everything we've output so far, and
+ turn on encryption for future data. On the input side, we
+ should only have unwrapped as far as the Gssapi-encrypt
+ command, so future unwrapping will become encrypted. */
buf_flush (buf_to_net, 1);
cvs_gssapi_encrypt = 1;
return;
@@ -2276,8 +2274,8 @@ serve_gssapi_authenticate (arg)
if (cvs_gssapi_wrapping)
{
/* We're already using a gssapi_wrap buffer for encryption.
- That includes authentication, so we don't have to do
- anything further. */
+ That includes authentication, so we don't have to do
+ anything further. */
return;
}
@@ -2292,7 +2290,9 @@ serve_gssapi_authenticate (arg)
}
#endif /* HAVE_GSSAPI */
-
+
+
+
#ifdef SERVER_FLOWCONTROL
/* The maximum we'll queue to the remote client before blocking. */
# ifndef SERVER_HI_WATER
@@ -2302,30 +2302,10 @@ serve_gssapi_authenticate (arg)
# ifndef SERVER_LO_WATER
# define SERVER_LO_WATER (1 * 1024 * 1024)
# endif /* SERVER_LO_WATER */
+#endif /* SERVER_FLOWCONTROL */
-static int set_nonblock_fd PROTO((int));
-
-/*
- * Set buffer BUF to non-blocking I/O. Returns 0 for success or errno
- * code.
- */
-
-static int
-set_nonblock_fd (fd)
- int fd;
-{
- int flags;
- flags = fcntl (fd, F_GETFL, 0);
- if (flags < 0)
- return errno;
- if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
- return errno;
- return 0;
-}
-#endif /* SERVER_FLOWCONTROL */
-
static void serve_questionable PROTO((char *));
static void
@@ -2367,15 +2347,8 @@ serve_questionable (arg)
}
}
-static void serve_case PROTO ((char *));
-static void
-serve_case (arg)
- char *arg;
-{
- ign_case = 1;
-}
-
+
static struct buffer *protocol;
/* This is the output which we are saving up to send to the server, in the
@@ -2445,48 +2418,48 @@ check_command_legal_p (cmd_name)
*/
#ifdef AUTH_SERVER_SUPPORT
if (CVS_Username == NULL)
- return 1;
+ return 1;
if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY)
{
- /* This command has the potential to modify the repository, so
- * we check if the user have permission to do that.
- *
- * (Only relevant for remote users -- local users can do
- * whatever normal Unix file permissions allow them to do.)
- *
- * The decision method:
- *
- * If $CVSROOT/CVSADMROOT_READERS exists and user is listed
- * in it, then read-only access for user.
- *
- * Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
- * listed in it, then also read-only access for user.
- *
- * Else read-write access for user.
- */
-
- char *linebuf = NULL;
- int num_red = 0;
- size_t linebuf_len = 0;
- char *fname;
- size_t flen;
- FILE *fp;
- int found_it = 0;
-
- /* else */
- flen = strlen (current_parsed_root->directory)
- + strlen (CVSROOTADM)
- + strlen (CVSROOTADM_READERS)
- + 3;
-
- fname = xmalloc (flen);
- (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
+ /* This command has the potential to modify the repository, so
+ * we check if the user have permission to do that.
+ *
+ * (Only relevant for remote users -- local users can do
+ * whatever normal Unix file permissions allow them to do.)
+ *
+ * The decision method:
+ *
+ * If $CVSROOT/CVSADMROOT_READERS exists and user is listed
+ * in it, then read-only access for user.
+ *
+ * Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
+ * listed in it, then also read-only access for user.
+ *
+ * Else read-write access for user.
+ */
+
+ char *linebuf = NULL;
+ int num_red = 0;
+ size_t linebuf_len = 0;
+ char *fname;
+ size_t flen;
+ FILE *fp;
+ int found_it = 0;
+
+ /* else */
+ flen = strlen (current_parsed_root->directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_READERS)
+ + 3;
+
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_READERS);
- fp = fopen (fname, "r");
+ fp = fopen (fname, "r");
- if (fp == NULL)
+ if (fp == NULL)
{
if (!existence_error (errno))
{
@@ -2497,51 +2470,51 @@ check_command_legal_p (cmd_name)
return 0;
}
}
- else /* successfully opened readers file */
- {
- while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
- {
- /* Hmmm, is it worth importing my own readline
- library into CVS? It takes care of chopping
- leading and trailing whitespace, "#" comments, and
- newlines automatically when so requested. Would
- save some code here... -kff */
-
- /* Chop newline by hand, for strcmp()'s sake. */
- if (linebuf[num_red - 1] == '\n')
- linebuf[num_red - 1] = '\0';
-
- if (strcmp (linebuf, CVS_Username) == 0)
- goto handle_illegal;
- }
+ else /* successfully opened readers file */
+ {
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Hmmm, is it worth importing my own readline
+ library into CVS? It takes care of chopping
+ leading and trailing whitespace, "#" comments, and
+ newlines automatically when so requested. Would
+ save some code here... -kff */
+
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ goto handle_illegal;
+ }
if (num_red < 0 && !feof (fp))
error (0, errno, "cannot read %s", fname);
- /* If not listed specifically as a reader, then this user
- has write access by default unless writers are also
- specified in a file . */
+ /* If not listed specifically as a reader, then this user
+ has write access by default unless writers are also
+ specified in a file . */
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
- }
+ }
free (fname);
/* Now check the writers file. */
- flen = strlen (current_parsed_root->directory)
- + strlen (CVSROOTADM)
- + strlen (CVSROOTADM_WRITERS)
- + 3;
+ flen = strlen (current_parsed_root->directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_WRITERS)
+ + 3;
- fname = xmalloc (flen);
- (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_WRITERS);
- fp = fopen (fname, "r");
+ fp = fopen (fname, "r");
- if (fp == NULL)
- {
+ if (fp == NULL)
+ {
if (linebuf)
- free (linebuf);
+ free (linebuf);
if (existence_error (errno))
{
/* Writers file does not exist, so everyone is a writer,
@@ -2557,43 +2530,43 @@ check_command_legal_p (cmd_name)
free (fname);
return 0;
}
- }
-
- found_it = 0;
- while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
- {
- /* Chop newline by hand, for strcmp()'s sake. */
- if (linebuf[num_red - 1] == '\n')
- linebuf[num_red - 1] = '\0';
-
- if (strcmp (linebuf, CVS_Username) == 0)
- {
- found_it = 1;
- break;
- }
- }
+ }
+
+ found_it = 0;
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ {
+ found_it = 1;
+ break;
+ }
+ }
if (num_red < 0 && !feof (fp))
error (0, errno, "cannot read %s", fname);
- if (found_it)
- {
- if (fclose (fp) < 0)
+ if (found_it)
+ {
+ if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
- if (linebuf)
- free (linebuf);
+ if (linebuf)
+ free (linebuf);
free (fname);
- return 1;
- }
- else /* writers file exists, but this user not listed in it */
- {
- handle_illegal:
- if (fclose (fp) < 0)
+ return 1;
+ }
+ else /* writers file exists, but this user not listed in it */
+ {
+ handle_illegal:
+ if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
- if (linebuf)
- free (linebuf);
+ if (linebuf)
+ free (linebuf);
free (fname);
return 0;
- }
+ }
}
#endif /* AUTH_SERVER_SUPPORT */
@@ -2602,16 +2575,40 @@ check_command_legal_p (cmd_name)
}
-
+
/* Execute COMMAND in a subprocess with the approriate funky things done. */
static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain;
+#ifdef SUNOS_KLUDGE
static int max_command_fd;
+#endif
#ifdef SERVER_FLOWCONTROL
static int flowcontrol_pipe[2];
#endif /* SERVER_FLOWCONTROL */
+
+
+/*
+ * Set buffer FD to non-blocking I/O. Returns 0 for success or errno
+ * code.
+ */
+int
+set_nonblock_fd (fd)
+ int fd;
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags < 0)
+ return errno;
+ if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ return errno;
+ return 0;
+}
+
+
+
static void
do_cvs_command (cmd_name, command)
char *cmd_name;
@@ -2650,7 +2647,7 @@ do_cvs_command (cmd_name, command)
if (print_pending_error ())
goto free_args_and_return;
- /* Global `command_name' is probably "server" right now -- only
+ /* Global `cvs_cmd_name' is probably "server" right now -- only
serve_export() sets it to anything else. So we will use local
parameter `cmd_name' to determine if this command is legal for
this user. */
@@ -2664,6 +2661,7 @@ do_cvs_command (cmd_name, command)
error \n");
goto free_args_and_return;
}
+ cvs_cmd_name = cmd_name;
(void) server_notify ();
@@ -2752,14 +2750,22 @@ error \n");
protocol_memory_error);
/* At this point we should no longer be using buf_to_net and
- buf_from_net. Instead, everything should go through
- protocol. */
- buf_to_net = NULL;
- buf_from_net = NULL;
+ buf_from_net. Instead, everything should go through
+ protocol. */
+ if (buf_to_net != NULL)
+ {
+ buf_free (buf_to_net);
+ buf_to_net = NULL;
+ }
+ if (buf_from_net != NULL)
+ {
+ buf_free (buf_from_net);
+ buf_from_net = NULL;
+ }
/* These were originally set up to use outbuf_memory_error.
- Since we're now in the child, we should use the simpler
- protocol_memory_error function. */
+ Since we're now in the child, we should use the simpler
+ protocol_memory_error function. */
saved_output->memory_error = protocol_memory_error;
saved_outerr->memory_error = protocol_memory_error;
@@ -2806,11 +2812,34 @@ error \n");
/* For now we just discard partial lines on stderr. I suspect
that CVS can't write such lines unless there is a bug. */
- /*
- * When we exit, that will close the pipes, giving an EOF to
- * the parent.
- */
buf_free (protocol);
+
+ /* Close the pipes explicitly in order to send an EOF to the parent,
+ * then wait for the parent to close the flow control pipe. This
+ * avoids a race condition where a child which dumped more than the
+ * high water mark into the pipes could complete its job and exit,
+ * leaving the parent process to attempt to write a stop byte to the
+ * closed flow control pipe, which earned the parent a SIGPIPE, which
+ * it normally only expects on the network pipe and that causes it to
+ * exit with an error message, rather than the SIGCHILD that it knows
+ * how to handle correctly.
+ */
+ /* Let exit() close STDIN - it's from /dev/null anyhow. */
+ fclose (stderr);
+ fclose (stdout);
+ close (protocol_pipe[1]);
+#ifdef SERVER_FLOWCONTROL
+ {
+ char junk;
+ ssize_t status;
+ while ((status = read (flowcontrol_pipe[0], &junk, 1)) > 0
+ || (status == -1 && errno == EAGAIN));
+ }
+ /* FIXME: No point in printing an error message with error(),
+ * as STDERR is already closed, but perhaps this could be syslogged?
+ */
+#endif
+
exit (exitstatus);
}
@@ -2837,7 +2866,9 @@ error \n");
FD_SET (protocol_pipe[0], &command_fds_to_drain.fds);
if (STDOUT_FILENO > num_to_check)
num_to_check = STDOUT_FILENO;
+#ifdef SUNOS_KLUDGE
max_command_fd = num_to_check;
+#endif
/*
* File descriptors are numbered from 0, so num_to_check needs to
* be one larger than the largest descriptor.
@@ -2981,8 +3012,8 @@ error \n");
child process. */
do {
/* This used to select on exceptions too, but as far
- as I know there was never any reason to do that and
- SCO doesn't let you select on exceptions on pipes. */
+ as I know there was never any reason to do that and
+ SCO doesn't let you select on exceptions on pipes. */
numfds = select (num_to_check, &readfds, &writefds,
(fd_set *)0, timeout_ptr);
if (numfds < 0
@@ -3082,9 +3113,9 @@ error \n");
if (stdout_pipe[0] >= 0
&& (FD_ISSET (stdout_pipe[0], &readfds)))
{
- int status;
+ int status;
- status = buf_input_data (stdoutbuf, (int *) NULL);
+ status = buf_input_data (stdoutbuf, (int *) NULL);
buf_copy_lines (buf_to_net, stdoutbuf, 'M');
@@ -3107,9 +3138,9 @@ error \n");
if (stderr_pipe[0] >= 0
&& (FD_ISSET (stderr_pipe[0], &readfds)))
{
- int status;
+ int status;
- status = buf_input_data (stderrbuf, (int *) NULL);
+ status = buf_input_data (stderrbuf, (int *) NULL);
buf_copy_lines (buf_to_net, stderrbuf, 'E');
@@ -3174,8 +3205,8 @@ error \n");
errs += WEXITSTATUS (status);
else
{
- int sig = WTERMSIG (status);
- char buf[50];
+ int sig = WTERMSIG (status);
+ char buf[50];
/*
* This is really evil, because signals might be numbered
* differently on the two systems. We should be using
@@ -3187,8 +3218,8 @@ error \n");
sprintf (buf, "%d\n", sig);
buf_output0 (buf_to_net, buf);
- /* Test for a core dump. Is this portable? */
- if (status & 0x80)
+ /* Test for a core dump. */
+ if (WCOREDUMP (status))
{
buf_output0 (buf_to_net, "E Core dumped; preserving ");
buf_output0 (buf_to_net, orig_server_temp_dir);
@@ -3327,28 +3358,30 @@ server_pause_check()
}
/* This assumes that we are using BSD or POSIX nonblocking
- I/O. System V nonblocking I/O returns zero if there is
- nothing to read. */
+ I/O. System V nonblocking I/O returns zero if there is
+ nothing to read. */
if (got == 0)
- error (1, 0, "flow control EOF");
+ error (1, 0, "flow control EOF");
if (got < 0 && ! blocking_error (errno))
{
- error (1, errno, "flow control read failed");
+ error (1, errno, "flow control read failed");
}
}
}
}
#endif /* SERVER_FLOWCONTROL */
-
+
/* This variable commented in server.h. */
char *server_dir = NULL;
-static void output_dir PROTO((char *, char *));
+
+
+static void output_dir PROTO((const char *, const char *));
static void
output_dir (update_dir, repository)
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
{
if (server_dir != NULL)
{
@@ -3363,7 +3396,9 @@ output_dir (update_dir, repository)
buf_output0 (protocol, repository);
buf_output0 (protocol, "/");
}
-
+
+
+
/*
* Entries line that we are squirreling away to send to the client when
* we are ready.
@@ -3382,15 +3417,17 @@ static char *scratched_file;
*/
static int kill_scratched_file;
+
+
void
server_register (name, version, timestamp, options, tag, date, conflict)
- char *name;
- char *version;
- char *timestamp;
- char *options;
- char *tag;
- char *date;
- char *conflict;
+ const char *name;
+ const char *version;
+ const char *timestamp;
+ const char *options;
+ const char *tag;
+ const char *date;
+ const char *conflict;
{
int len;
@@ -3456,9 +3493,11 @@ server_register (name, version, timestamp, options, tag, date, conflict)
}
}
+
+
void
server_scratch (fname)
- char *fname;
+ const char *fname;
{
/*
* I have reports of Scratch_Entry and Register both happening, in
@@ -3556,9 +3595,9 @@ checked_in_response (file, update_dir, repository)
void
server_checked_in (file, update_dir, repository)
- char *file;
- char *update_dir;
- char *repository;
+ const char *file;
+ const char *update_dir;
+ const char *repository;
{
if (noexec)
return;
@@ -3584,9 +3623,9 @@ server_checked_in (file, update_dir, repository)
void
server_update_entries (file, update_dir, repository, updated)
- char *file;
- char *update_dir;
- char *repository;
+ const char *file;
+ const char *update_dir;
+ const char *repository;
enum server_updated_arg4 updated;
{
if (noexec)
@@ -3632,8 +3671,6 @@ static void
serve_rlog (arg)
char *arg;
{
- /* Tell cvslog() to behave like rlog not log. */
- command_name = "rlog";
do_cvs_command ("rlog", cvslog);
}
@@ -3676,8 +3713,6 @@ static void
serve_rtag (arg)
char *arg;
{
- /* Tell cvstag() to behave like rtag not tag. */
- command_name = "rtag";
do_cvs_command ("rtag", cvstag);
}
@@ -3843,8 +3878,6 @@ static void
serve_rannotate (arg)
char *arg;
{
- /* Tell annotate() to behave like rannotate not annotate. */
- command_name = "rannotate";
do_cvs_command ("rannotate", annotate);
}
@@ -3895,14 +3928,14 @@ serve_co (arg)
free (tempdir);
}
- /* Compensate for server_export()'s setting of command_name.
+ /* Compensate for server_export()'s setting of cvs_cmd_name.
*
* [It probably doesn't matter if do_cvs_command() gets "export"
* or "checkout", but we ought to be accurate where possible.]
*/
- do_cvs_command ((strcmp (command_name, "export") == 0) ?
- "export" : "checkout",
- checkout);
+ do_cvs_command ((strcmp (cvs_cmd_name, "export") == 0) ?
+ "export" : "checkout",
+ checkout);
}
static void
@@ -3910,16 +3943,18 @@ serve_export (arg)
char *arg;
{
/* Tell checkout() to behave like export not checkout. */
- command_name = "export";
+ cvs_cmd_name = "export";
serve_co (arg);
}
-
+
+
+
void
server_copy_file (file, update_dir, repository, newfile)
- char *file;
- char *update_dir;
- char *repository;
- char *newfile;
+ const char *file;
+ const char *update_dir;
+ const char *repository;
+ const char *newfile;
{
/* At least for now, our practice is to have the server enforce
noexec for the repository and the client enforce it for the
@@ -4059,10 +4094,10 @@ CVS server internal error: no mode in server_updated");
if (checksum_supported)
{
- int i;
+ int i;
char buf[3];
- buf_output0 (protocol, "Checksum ");
+ buf_output0 (protocol, "Checksum ");
for (i = 0; i < 16; i++)
{
sprintf (buf, "%02x", (unsigned int) checksum[i]);
@@ -4093,7 +4128,7 @@ CVS server internal error: no mode in server_updated");
in case we end up processing it again (e.g. modules3-6
in the testsuite). */
node = findnode_fn (finfo->entries, finfo->file);
- entnode = (Entnode *)node->data;
+ entnode = node->data;
free (entnode->timestamp);
entnode->timestamp = xstrdup ("=");
}
@@ -4111,7 +4146,7 @@ CVS server internal error: no mode in server_updated");
new_entries_line ();
- {
+ {
char *mode_string;
mode_string = mode_to_string (mode);
@@ -4151,9 +4186,9 @@ CVS server internal error: no mode in server_updated");
int fd;
/* Callers must avoid passing us a buffer if
- file_gzip_level is set. We could handle this case,
- but it's not worth it since this case never arises
- with a current client and server. */
+ file_gzip_level is set. We could handle this case,
+ but it's not worth it since this case never arises
+ with a current client and server. */
if (filebuf != NULL)
error (1, 0, "\
CVS server internal error: unhandled case in server_updated");
@@ -4203,7 +4238,6 @@ CVS server internal error: unhandled case in server_updated");
else
{
buf_append_buffer (protocol, filebuf);
- buf_free (filebuf);
}
/* Note we only send a newline here if the file ended with one. */
@@ -4284,10 +4318,12 @@ server_use_rcs_diff ()
return supported_response ("Rcs-diff");
}
+
+
void
server_set_entstat (update_dir, repository)
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
{
static int set_static_supported = -1;
if (set_static_supported == -1)
@@ -4300,10 +4336,12 @@ server_set_entstat (update_dir, repository)
buf_send_counted (protocol);
}
+
+
void
server_clear_entstat (update_dir, repository)
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
{
static int clear_static_supported = -1;
if (clear_static_supported == -1)
@@ -4318,13 +4356,15 @@ server_clear_entstat (update_dir, repository)
buf_output0 (protocol, "\n");
buf_send_counted (protocol);
}
-
+
+
+
void
server_set_sticky (update_dir, repository, tag, date, nonbranch)
- char *update_dir;
- char *repository;
- char *tag;
- char *date;
+ const char *update_dir;
+ const char *repository;
+ const char *tag;
+ const char *date;
int nonbranch;
{
static int set_sticky_supported = -1;
@@ -4369,8 +4409,8 @@ server_set_sticky (update_dir, repository, tag, date, nonbranch)
struct template_proc_data
{
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
};
/* Here as a static until we get around to fixing Parse_Info to pass along
@@ -4419,15 +4459,18 @@ template_proc (repository, template)
return 1;
}
}
+ buf_send_counted (protocol);
if (fclose (fp) < 0)
error (0, errno, "cannot close rcsinfo template file %s", template);
return 0;
}
+
+
void
server_template (update_dir, repository)
- char *update_dir;
- char *repository;
+ const char *update_dir;
+ const char *repository;
{
struct template_proc_data data;
data.update_dir = update_dir;
@@ -4435,7 +4478,9 @@ server_template (update_dir, repository)
tpd = &data;
(void) Parse_Info (CVSROOTADM_RCSINFO, repository, template_proc, 1);
}
-
+
+
+
static void
serve_gzip_contents (arg)
char *arg;
@@ -4480,8 +4525,8 @@ serve_wrapper_sendme_rcs_options (arg)
wrap_setup ();
for (wrap_unparse_rcs_options (&wrapper_line, 1);
- wrapper_line;
- wrap_unparse_rcs_options (&wrapper_line, 0))
+ wrapper_line;
+ wrap_unparse_rcs_options (&wrapper_line, 0))
{
buf_output0 (buf_to_net, "Wrapper-rcsOption ");
buf_output0 (buf_to_net, wrapper_line);
@@ -4548,7 +4593,7 @@ expand_proc (argc, argv, where, mwhere, mfile, shorten,
else
{
/* We may not need to do this anymore -- check the definition
- of aliases before removing */
+ of aliases before removing */
if (argc == 1)
{
buf_output0 (buf_to_net, "Module-expansion ");
@@ -4564,7 +4609,7 @@ expand_proc (argc, argv, where, mwhere, mfile, shorten,
{
for (i = 1; i < argc; ++i)
{
- buf_output0 (buf_to_net, "Module-expansion ");
+ buf_output0 (buf_to_net, "Module-expansion ");
if (server_dir != NULL)
{
buf_output0 (buf_to_net, server_dir);
@@ -4617,112 +4662,8 @@ serve_expand_modules (arg)
buf_flush (buf_to_net, 1);
}
-void
-server_prog (dir, name, which)
- char *dir;
- char *name;
- enum progs which;
-{
- if (!supported_response ("Set-checkin-prog"))
- {
- buf_output0 (protocol, "E \
-warning: this client does not support -i or -u flags in the modules file.\n");
- return;
- }
- switch (which)
- {
- case PROG_CHECKIN:
- buf_output0 (protocol, "Set-checkin-prog ");
- break;
- case PROG_UPDATE:
- buf_output0 (protocol, "Set-update-prog ");
- break;
- }
- buf_output0 (protocol, dir);
- buf_append_char (protocol, '\n');
- buf_output0 (protocol, name);
- buf_append_char (protocol, '\n');
- buf_send_counted (protocol);
-}
-
-static void
-serve_checkin_prog (arg)
- char *arg;
-{
- FILE *f;
- f = CVS_FOPEN (CVSADM_CIPROG, "w+");
- if (f == NULL)
- {
- 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)
- {
- 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)
- {
- 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;
- }
-}
-
-static void
-serve_update_prog (arg)
- char *arg;
-{
- FILE *f;
- /* Before we do anything we need to make sure we are not in readonly
- mode. */
- if (!check_command_legal_p ("commit"))
- {
- /* I might be willing to make this a warning, except we lack the
- machinery to do so. */
- if (alloc_pending (80))
- sprintf (pending_error_text, "\
-E Flag -u in modules not allowed in readonly mode");
- return;
- }
- f = CVS_FOPEN (CVSADM_UPROG, "w+");
- if (f == NULL)
- {
- 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)
- {
- 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)
- {
- 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;
- }
-}
-
static void serve_valid_requests PROTO((char *arg));
#endif /* SERVER_SUPPORT */
@@ -4752,8 +4693,6 @@ struct request requests[] =
REQ_LINE("Max-dotdot", serve_max_dotdot, 0),
REQ_LINE("Static-directory", serve_static_directory, 0),
REQ_LINE("Sticky", serve_sticky, 0),
- REQ_LINE("Checkin-prog", serve_noop, 0),
- REQ_LINE("Update-prog", serve_noop, 0),
REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL),
REQ_LINE("Kopt", serve_kopt, 0),
REQ_LINE("Checkin-time", serve_checkin_time, 0),
@@ -4768,14 +4707,13 @@ struct request requests[] =
REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL),
REQ_LINE("Notify", serve_notify, 0),
REQ_LINE("Questionable", serve_questionable, 0),
- 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, RQ_ROOTLESS),
REQ_LINE("Gzip-stream", serve_gzip_stream, 0),
REQ_LINE("wrapper-sendme-rcsOptions",
- serve_wrapper_sendme_rcs_options,
- 0),
+ serve_wrapper_sendme_rcs_options,
+ 0),
REQ_LINE("Set", serve_set, RQ_ROOTLESS),
#ifdef ENCRYPTION
# ifdef HAVE_KERBEROS
@@ -4889,25 +4827,27 @@ server_cleanup (sig)
* have generated any final output, we shut down BUF_TO_NET.
*/
- status = buf_shutdown (buf_from_net);
- if (status != 0)
- error (0, status, "shutting down buffer from client");
- buf_free (buf_from_net);
- buf_from_net = NULL;
- }
+ if (buf_from_net != NULL)
+ {
+ status = buf_shutdown (buf_from_net);
+ if (status != 0)
+ error (0, status, "shutting down buffer from client");
+ buf_free (buf_from_net);
+ buf_from_net = NULL;
+ }
- if (dont_delete_temp)
- {
- if (buf_to_net != NULL)
+ if (dont_delete_temp)
{
(void) buf_flush (buf_to_net, 1);
(void) buf_shutdown (buf_to_net);
buf_free (buf_to_net);
buf_to_net = NULL;
error_use_protocol = 0;
+ return;
}
- return;
}
+ else if (dont_delete_temp)
+ return;
/* What a bogus kludge. This disgusting code makes all kinds of
assumptions about SunOS, and is only for a bug in that system.
@@ -5099,13 +5039,13 @@ error ENOMEM Virtual memory exhausted.\n");
orig_server_temp_dir = server_temp_dir;
/* Create the temporary directory, and set the mode to
- 700, to discourage random people from tampering with
- it. */
+ 700, to discourage random people from tampering with
+ it. */
while ((status = mkdir_p (server_temp_dir)) == EEXIST)
{
- static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
+ static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
- if (i >= sizeof suffix - 1) break;
+ if (i >= sizeof suffix - 1) break;
if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
p[0] = suffix[i++];
p[1] = '\0';
@@ -5145,8 +5085,7 @@ error ENOMEM Virtual memory exhausted.\n");
/* Small for testing. */
argument_vector_size = 1;
- argument_vector =
- (char **) xmalloc (argument_vector_size * sizeof (char *));
+ argument_vector = xmalloc (argument_vector_size * sizeof (char *));
argument_count = 1;
/* This gets printed if the client supports an option which the
server doesn't, causing the server to print a usage message.
@@ -5155,7 +5094,7 @@ error ENOMEM Virtual memory exhausted.\n");
by options which are for a particular command. Might be nice to
say something like "client apparently supports an option not supported
by this server" or something like that instead of usage message. */
- error_prog_name = xmalloc( strlen(program_name) + 8 );
+ error_prog_name = xmalloc (strlen (program_name) + 8);
sprintf(error_prog_name, "%s server", program_name);
argument_vector[0] = error_prog_name;
@@ -5165,7 +5104,7 @@ error ENOMEM Virtual memory exhausted.\n");
struct request *rq;
int status;
- status = buf_read_line (buf_from_net, &cmd, (int *) NULL);
+ status = buf_read_line (buf_from_net, &cmd, NULL);
if (status == -2)
{
buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\
@@ -5222,7 +5161,7 @@ error ENOMEM Virtual memory exhausted.\n");
{
if (!print_pending_error ())
{
- buf_output0 (buf_to_net, "error unrecognized request `");
+ buf_output0 (buf_to_net, "error unrecognized request `");
buf_output0 (buf_to_net, cmd);
buf_append_char (buf_to_net, '\'');
buf_append_char (buf_to_net, '\n');
@@ -5230,12 +5169,33 @@ error ENOMEM Virtual memory exhausted.\n");
}
free (orig_cmd);
}
- free(error_prog_name);
+ free (error_prog_name);
+
+ /* We expect the client is done talking to us at this point. If there is
+ * any data in the buffer or on the network pipe, then something we didn't
+ * prepare for is happening.
+ */
+ if (!buf_empty (buf_from_net))
+ {
+ /* Try to send the error message to the client, but also syslog it, in
+ * case the client isn't listening anymore.
+ */
+#ifdef HAVE_SYSLOG_H
+ /* FIXME: Can the IP address of the connecting client be retrieved
+ * and printed here?
+ */
+ syslog (LOG_DAEMON | LOG_ERR, "Dying gasps received from client.");
+#endif
+ error (0, 0, "Dying gasps received from client.");
+ }
+
+ /* This command will actually close the network buffers. */
server_cleanup (0);
return 0;
}
-
+
+
#if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
static void switch_to_user PROTO((const char *, const char *));
@@ -5249,11 +5209,11 @@ switch_to_user (cvs_username, username)
pw = getpwnam (username);
if (pw == NULL)
{
- /* Normally this won't be reached; check_password contains
- a similar check. */
+ /* check_password contains a similar check, so this usually won't be
+ reached unless the CVS user is mapped to an invalid system user. */
printf ("E Fatal error, aborting.\n\
-error 0 %s: no such user\n", username);
+error 0 %s: no such system user\n", username);
/* Don't worry about server_cleanup; server_active isn't set yet. */
error_exit ();
}
@@ -5312,6 +5272,11 @@ error 0 %s: no such user\n", username);
{
/* See comments at setuid call below for more discussion. */
printf ("error 0 setgid failed: %s\n", strerror (errno));
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR,
+ "setgid to %d failed (%m): real %d/%d, effective %d/%d ",
+ pw->pw_gid, getuid(), getgid(), geteuid(), getegid());
+#endif
/* Don't worry about server_cleanup;
server_active isn't set yet. */
error_exit ();
@@ -5327,6 +5292,11 @@ error 0 %s: no such user\n", username);
it does mean that some people might need to update their
CVSROOT/passwd file. */
printf ("error 0 setuid failed: %s\n", strerror (errno));
+#ifdef HAVE_SYSLOG_H
+ syslog (LOG_DAEMON | LOG_ERR,
+ "setuid to %d failed (%m): real %d/%d, effective %d/%d ",
+ pw->pw_uid, getuid(), getgid(), geteuid(), getegid());
+#endif
/* Don't worry about server_cleanup; server_active isn't set yet. */
error_exit ();
}
@@ -5357,9 +5327,9 @@ error 0 %s: no such user\n", username);
(void) putenv (env);
#ifdef AUTH_SERVER_SUPPORT
- env = xmalloc (sizeof "CVS_USER=" + strlen (CVS_Username));
- (void) sprintf (env, "CVS_USER=%s", CVS_Username);
- (void) putenv (env);
+ env = xmalloc (sizeof "CVS_USER=" + strlen (CVS_Username));
+ (void) sprintf (env, "CVS_USER=%s", CVS_Username);
+ (void) putenv (env);
#endif
}
#endif /* HAVE_PUTENV */
@@ -5408,7 +5378,7 @@ check_repository_password (username, password, repository, host_user_ptr)
+ 1);
(void) sprintf (filename, "%s/%s/%s", repository,
- CVSROOTADM, CVSROOTADM_PASSWD);
+ CVSROOTADM, CVSROOTADM_PASSWD);
fp = CVS_FOPEN (filename, "r");
if (fp == NULL)
@@ -5424,10 +5394,10 @@ check_repository_password (username, password, repository, host_user_ptr)
{
if ((strncmp (linebuf, username, namelen) == 0)
&& (linebuf[namelen] == ':'))
- {
+ {
found_it = 1;
break;
- }
+ }
}
if (ferror (fp))
error (0, errno, "cannot read %s", filename);
@@ -5438,78 +5408,83 @@ check_repository_password (username, password, repository, host_user_ptr)
if (found_it)
{
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. */
+ 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, ":");
- }
-
- /* Of course, maybe there was no system user portion... */
+ 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, ":");
+ }
+
+ /* Of course, maybe there was no system user portion... */
if (host_user_tmp == NULL)
- host_user_tmp = username;
-
- /* 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);
+ host_user_tmp = username;
+
+ /* 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);
retval = 1;
- }
+ }
else
- {
- *host_user_ptr = NULL;
- retval = 2;
- }
+ {
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "password mismatch for %s in %s: %s vs. %s", username,
+ repository, crypt(password, found_password), found_password);
+#endif
+ *host_user_ptr = NULL;
+ retval = 2;
+ }
}
else /* Didn't find this user, so deny access. */
{
@@ -5519,12 +5494,13 @@ check_repository_password (username, password, repository, host_user_ptr)
free (filename);
if (linebuf)
- free (linebuf);
+ free (linebuf);
return retval;
}
+
/* Return a hosting username if password matches, else NULL. */
static char *
check_password (username, password, repository)
@@ -5532,6 +5508,8 @@ check_password (username, password, repository)
{
int rc;
char *host_user = NULL;
+ char *found_passwd = NULL;
+ struct passwd *pw;
/* First we see if this user has a password in the CVS-specific
password file. If so, that's enough to authenticate with. If
@@ -5546,20 +5524,31 @@ check_password (username, password, repository)
if (rc == 2)
return NULL;
- /* else */
-
if (rc == 1)
{
- /* host_user already set by reference, so just return. */
- goto handle_return;
+ /* host_user already set by reference, so just return. */
+ goto handle_return;
}
- else if (rc == 0 && system_auth)
+
+ assert (rc == 0);
+
+ if (!system_auth)
{
- /* No cvs password found, so try /etc/passwd. */
+ /* Note that the message _does_ distinguish between the case in
+ which we check for a system password and the case in which
+ we do not. It is a real pain to track down why it isn't
+ letting you in if it won't say why, and I am not convinced
+ that the potential information disclosure to an attacker
+ outweighs this. */
+ printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
+
+ error_exit ();
+ }
+
+ /* No cvs password found, so try /etc/passwd. */
- char *found_passwd = NULL;
- struct passwd *pw;
#ifdef HAVE_GETSPNAM
+ {
struct spwd *spw;
spw = getspnam (username);
@@ -5567,85 +5556,78 @@ check_password (username, password, repository)
{
found_passwd = spw->sp_pwdp;
}
+ }
#endif
- if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
- {
- found_passwd = pw->pw_passwd;
- }
+ if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
+ {
+ found_passwd = pw->pw_passwd;
+ }
- if (found_passwd == NULL)
- {
- printf ("E Fatal error, aborting.\n\
+ if (found_passwd == NULL)
+ {
+ printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", username);
- error_exit ();
- }
+ error_exit ();
+ }
- /* Allow for dain bramaged HPUX passwd aging
- * - Basically, HPUX adds a comma and some data
- * about whether the passwd has expired or not
- * on the end of the passwd field.
- * - This code replaces the ',' with '\0'.
- *
- * FIXME - our workaround is brain damaged too. I'm
- * guessing that HPUX WANTED other systems to think the
- * password was wrong so logins would fail if the
- * system didn't handle expired passwds and the passwd
- * might be expired. I think the way to go here
- * is with PAM.
- */
- strtok (found_passwd, ",");
-
- if (*found_passwd)
- {
- /* user exists and has a password */
- host_user = ((! strcmp (found_passwd,
- crypt (password, found_passwd)))
- ? xstrdup (username) : NULL);
- goto handle_return;
- }
- else if (password && *password)
- {
- /* user exists and has no system password, but we got
- one as parameter */
+ /* Allow for dain bramaged HPUX passwd aging
+ * - Basically, HPUX adds a comma and some data
+ * about whether the passwd has expired or not
+ * on the end of the passwd field.
+ * - This code replaces the ',' with '\0'.
+ *
+ * FIXME - our workaround is brain damaged too. I'm
+ * guessing that HPUX WANTED other systems to think the
+ * password was wrong so logins would fail if the
+ * system didn't handle expired passwds and the passwd
+ * might be expired. I think the way to go here
+ * is with PAM.
+ */
+ strtok (found_passwd, ",");
+
+ if (*found_passwd)
+ {
+ /* user exists and has a password */
+ if (strcmp (found_passwd, crypt (password, found_passwd)) == 0)
+ {
host_user = xstrdup (username);
- goto handle_return;
- }
+ }
else
- {
- /* user exists but has no password at all */
+ {
host_user = NULL;
- goto handle_return;
- }
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "password mismatch for %s: %s vs. %s", username,
+ crypt(password, found_passwd), found_passwd);
+#endif
+ }
+ goto handle_return;
}
- else if (rc == 0)
- {
- /* Note that the message _does_ distinguish between the case in
- which we check for a system password and the case in which
- we do not. It is a real pain to track down why it isn't
- letting you in if it won't say why, and I am not convinced
- that the potential information disclosure to an attacker
- outweighs this. */
- printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
- error_exit ();
- }
- else
+ if (password && *password)
{
- /* Something strange happened. We don't know what it was, but
- we certainly won't grant authorization. */
- host_user = NULL;
- goto handle_return;
+ /* user exists and has no system password, but we got
+ one as parameter */
+ host_user = xstrdup (username);
+ goto handle_return;
}
+ /* user exists but has no password at all */
+ host_user = NULL;
+#ifdef LOG_AUTHPRIV
+ syslog (LOG_AUTHPRIV | LOG_NOTICE,
+ "login refused for %s: user has no password", username);
+#endif
+
handle_return:
if (host_user)
{
- /* Set CVS_Username here, in allocated space.
- It might or might not be the same as host_user. */
- CVS_Username = xmalloc (strlen (username) + 1);
- strcpy (CVS_Username, username);
+ /* Set CVS_Username here, in allocated space.
+ It might or might not be the same as host_user. */
+ CVS_Username = xmalloc (strlen (username) + 1);
+ strcpy (CVS_Username, username);
}
return host_user;
@@ -5700,7 +5682,7 @@ pserver_authenticate_connection ()
*
* BEGIN VERIFICATION REQUEST\n
*
- * and
+ * and
*
* END VERIFICATION REQUEST\n
*
@@ -5772,10 +5754,16 @@ pserver_authenticate_connection ()
getline_safe (&username, &username_allocated, stdin, PATH_MAX);
getline_safe (&password, &password_allocated, stdin, PATH_MAX);
- /* Make them pure. */
- strip_trailing_newlines (repository);
- strip_trailing_newlines (username);
- strip_trailing_newlines (password);
+ /* Make them pure.
+ *
+ * We check that none of the lines were truncated by getnline in order
+ * to be sure that we don't accidentally allow a blind DOS attack to
+ * authenticate, however slim the odds of that might be.
+ */
+ if (!strip_trailing_newlines (repository)
+ || !strip_trailing_newlines (username)
+ || !strip_trailing_newlines (password))
+ error (1, 0, "Maximum line length exceeded during authentication.");
/* ... and make sure the protocol ends on the right foot. */
/* See above comment about error handling. */
@@ -5810,10 +5798,6 @@ pserver_authenticate_connection ()
{
#ifdef HAVE_SYSLOG_H
syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository);
-#ifdef LOG_AUTHPRIV
- syslog (LOG_AUTHPRIV | LOG_NOTICE, "login failure by %s / %s (for %s)",
- username, descrambled_password, repository);
-#endif
#endif
memset (descrambled_password, 0, strlen (descrambled_password));
free (descrambled_password);
@@ -5930,7 +5914,7 @@ error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status));
}
/* Switch to run as this user. */
- switch_to_user (user);
+ switch_to_user ("Kerberos 4", user);
}
#endif /* HAVE_KERBEROS */
@@ -5951,6 +5935,8 @@ gserver_authenticate_connection ()
struct hostent *hp;
gss_buffer_desc tok_in, tok_out;
char buf[1024];
+ char *credbuf;
+ size_t credbuflen;
OM_uint32 stat_min, ret;
gss_name_t server_name, client_name;
gss_cred_id_t server_creds;
@@ -5985,26 +5971,35 @@ gserver_authenticate_connection ()
error (1, errno, "read of length failed");
nbytes = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff);
- assert (nbytes <= sizeof buf);
-
- if (fread (buf, 1, nbytes, stdin) != nbytes)
+ if (nbytes <= sizeof buf)
+ {
+ credbuf = buf;
+ credbuflen = sizeof buf;
+ }
+ else
+ {
+ credbuflen = nbytes;
+ credbuf = xmalloc (credbuflen);
+ }
+
+ if (fread (credbuf, 1, nbytes, stdin) != nbytes)
error (1, errno, "read of data failed");
gcontext = GSS_C_NO_CONTEXT;
tok_in.length = nbytes;
- tok_in.value = buf;
+ tok_in.value = credbuf;
if (gss_accept_sec_context (&stat_min,
- &gcontext, /* context_handle */
- server_creds, /* verifier_cred_handle */
- &tok_in, /* input_token */
- NULL, /* channel bindings */
- &client_name, /* src_name */
- &mechid, /* mech_type */
- &tok_out, /* output_token */
- &ret,
- NULL, /* ignore time_rec */
- NULL) /* ignore del_cred_handle */
+ &gcontext, /* context_handle */
+ server_creds, /* verifier_cred_handle */
+ &tok_in, /* input_token */
+ NULL, /* channel bindings */
+ &client_name, /* src_name */
+ &mechid, /* mech_type */
+ &tok_out, /* output_token */
+ &ret,
+ NULL, /* ignore time_rec */
+ NULL) /* ignore del_cred_handle */
!= GSS_S_COMPLETE)
{
error (1, 0, "could not verify credentials");
@@ -6044,6 +6039,9 @@ gserver_authenticate_connection ()
switch_to_user ("GSSAPI", buf);
+ if (credbuf != buf)
+ free (credbuf);
+
printf ("I LOVE YOU\n");
fflush (stdout);
}
@@ -6435,8 +6433,9 @@ this client does not support writing binary files to stdout");
}
}
-/* Like CVS_OUTPUT but output is for stderr not stdout. */
+
+/* Like CVS_OUTPUT but output is for stderr not stdout. */
void
cvs_outerr (str, len)
const char *str;
@@ -6480,10 +6479,11 @@ cvs_outerr (str, len)
}
}
+
+
/* Flush stderr. stderr is normally flushed automatically, of course,
but this function is used to flush information from the server back
to the client. */
-
void
cvs_flusherr ()
{
@@ -6510,10 +6510,11 @@ cvs_flusherr ()
fflush (stderr);
}
+
+
/* Make it possible for the user to see what has been written to
stdout (it is up to the implementation to decide exactly how far it
should go to ensure this). */
-
void
cvs_flushout ()
{
@@ -6552,8 +6553,8 @@ cvs_flushout ()
void
cvs_output_tagged (tag, text)
- char *tag;
- char *text;
+ const char *tag;
+ const char *text;
{
if (text != NULL && strchr (text, '\n') != NULL)
/* Uh oh. The protocol has no way to cope with this. For now
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index 426cf70..479dde0 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -51,30 +51,29 @@ static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
int adding, int merging, int update_server));
#ifdef SERVER_SUPPORT
static void checkout_to_buffer PROTO ((void *, const char *, size_t));
-#endif
-#ifdef SERVER_SUPPORT
static int patch_file PROTO ((struct file_info *finfo,
Vers_TS *vers_ts,
int *docheckout, struct stat *file_info,
unsigned char *checksum));
static void patch_file_write PROTO ((void *, const char *, size_t));
-#endif
+#endif /* SERVER_SUPPORT */
static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers));
-static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir,
- char *repository, char *update_dir,
- List *entries));
-static int update_dirleave_proc PROTO ((void *callerdat, char *dir,
- int err, char *update_dir,
+static Dtype update_dirent_proc PROTO ((void *callerdat, const char *dir,
+ const char *repository,
+ const char *update_dir,
+ List *entries));
+static int update_dirleave_proc PROTO ((void *callerdat, const char *dir,
+ int err, const char *update_dir,
List *entries));
static int update_fileproc PROTO ((void *callerdat, struct file_info *));
static int update_filesdone_proc PROTO ((void *callerdat, int err,
- char *repository, char *update_dir,
- List *entries));
+ const char *repository,
+ const char *update_dir,
+ List *entries));
#ifdef PRESERVE_PERMISSIONS_SUPPORT
static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *));
#endif
-static void write_letter PROTO ((struct file_info *finfo, int letter));
static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
static char *options = NULL;
@@ -188,7 +187,7 @@ update (argc, argv)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
- command_name);
+ cvs_cmd_name);
break;
case 'T':
xpull_template = 1;
@@ -422,7 +421,7 @@ update (argc, argv)
err = do_update (argc, argv, options, tag, date, force_tag_match,
local, update_build_dirs, aflag, update_prune_dirs,
pipeout, which, join_rev1, join_rev2, (char *) NULL,
- xpull_template);
+ xpull_template, (char *) NULL);
/* free the space Make_Date allocated if necessary */
if (date != NULL)
@@ -437,7 +436,7 @@ update (argc, argv)
int
do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir,
- xpull_template)
+ xpull_template, repository)
int argc;
char **argv;
char *xoptions;
@@ -454,6 +453,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
char *xjoin_rev2;
char *preload_update_dir;
int xpull_template;
+ char *repository;
{
int err = 0;
char *cp;
@@ -501,7 +501,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL,
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, which, aflag, CVS_LOCK_READ,
- preload_update_dir, 1);
+ preload_update_dir, 1, (char *) NULL);
if (err)
return (err);
@@ -517,7 +517,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
err = start_recursion (update_fileproc, update_filesdone_proc,
update_dirent_proc, update_dirleave_proc, NULL,
argc, argv, local, which, aflag, CVS_LOCK_READ,
- preload_update_dir, 1);
+ preload_update_dir, 1, repository);
#ifdef SERVER_SUPPORT
if (server_active)
@@ -570,12 +570,14 @@ get_linkinfo_proc (callerdat, finfo)
hlinfo->status = (Ctype) 0; /* is this dumb? */
hlinfo->checked_out = 0;
- linkp->data = (char *) hlinfo;
+ linkp->data = hlinfo;
return 0;
}
#endif
+
+
/*
* This is the callback proc for update. It is called for each file in each
* directory by the recursion code. The current directory is the local
@@ -698,38 +700,8 @@ update_fileproc (callerdat, finfo)
{
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.
- */
-
-#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);
- }
-#else
- 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)
+ if (file_has_conflict (finfo, vers->ts_conflict)
+ || file_has_markers (finfo))
{
write_letter (finfo, 'C');
retval = 1;
@@ -744,10 +716,7 @@ update_fileproc (callerdat, finfo)
}
}
if (!retval)
- {
write_letter (finfo, 'M');
- retval = 0;
- }
}
break;
case T_PATCH: /* needs patch */
@@ -817,42 +786,48 @@ update_fileproc (callerdat, finfo)
}
freevers_ts (&vers);
- return (retval);
+ return retval;
}
-static void update_ignproc PROTO ((char *, char *));
+
+
+static void update_ignproc PROTO ((const char *, const char *));
static void
update_ignproc (file, dir)
- char *file;
- char *dir;
+ const char *file;
+ const char *dir;
{
struct file_info finfo;
+ char *tmp;
memset (&finfo, 0, sizeof (finfo));
finfo.file = file;
finfo.update_dir = dir;
if (dir[0] == '\0')
- finfo.fullname = xstrdup (file);
+ tmp = xstrdup (file);
else
{
- finfo.fullname = xmalloc (strlen (file) + strlen (dir) + 10);
- strcpy (finfo.fullname, dir);
- strcat (finfo.fullname, "/");
- strcat (finfo.fullname, file);
+ tmp = xmalloc (strlen (file) + strlen (dir) + 10);
+ strcpy (tmp, dir);
+ strcat (tmp, "/");
+ strcat (tmp, file);
}
+ finfo.fullname = tmp;
write_letter (&finfo, '?');
- free (finfo.fullname);
+ free (tmp);
}
+
+
/* ARGSUSED */
static int
update_filesdone_proc (callerdat, err, repository, update_dir, entries)
void *callerdat;
int err;
- char *repository;
- char *update_dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
if (rewrite_tag)
@@ -869,7 +844,7 @@ update_filesdone_proc (callerdat, err, repository, update_dir, entries)
}
/* Clean up CVS admin dirs if we are export */
- if (strcmp (command_name, "export") == 0)
+ if (strcmp (cvs_cmd_name, "export") == 0)
{
/* I'm not sure the existence_error is actually possible (except
in cases where we really should print a message), but since
@@ -891,6 +866,8 @@ update_filesdone_proc (callerdat, err, repository, update_dir, entries)
return (err);
}
+
+
/*
* update_dirent_proc () is called back by the recursion processor before a
* sub-directory is processed for update. In this case, update_dirent proc
@@ -902,9 +879,9 @@ update_filesdone_proc (callerdat, err, repository, update_dir, entries)
static Dtype
update_dirent_proc (callerdat, dir, repository, update_dir, entries)
void *callerdat;
- char *dir;
- char *repository;
- char *update_dir;
+ const char *dir;
+ const char *repository;
+ const char *update_dir;
List *entries;
{
if (ignore_directory (update_dir))
@@ -1054,6 +1031,8 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
return (R_PROCESS);
}
+
+
/*
* update_dirleave_proc () is called back by the recursion code upon leaving
* a directory. It will prune empty directories if needed and will execute
@@ -1063,13 +1042,11 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
static int
update_dirleave_proc (callerdat, dir, err, update_dir, entries)
void *callerdat;
- char *dir;
+ const char *dir;
int err;
- char *update_dir;
+ const char *update_dir;
List *entries;
{
- FILE *fp;
-
/* Delete the ignore list if it hasn't already been done. */
if (ignlist)
dellist (&ignlist);
@@ -1095,45 +1072,6 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
tag_update_dir = NULL;
}
- /* run the update_prog if there is one */
- /* FIXME: should be checking for errors from CVS_FOPEN and printing
- them if not existence_error. */
- if (err == 0 && !pipeout && !noexec &&
- (fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL)
- {
- char *cp;
- char *repository;
- char *line = NULL;
- size_t line_allocated = 0;
-
- repository = Name_Repository ((char *) NULL, update_dir);
- if (getline (&line, &line_allocated, fp) >= 0)
- {
- if ((cp = strrchr (line, '\n')) != NULL)
- *cp = '\0';
- run_setup (line);
- run_arg (repository);
- cvs_output (program_name, 0);
- cvs_output (" ", 1);
- cvs_output (command_name, 0);
- 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))
- error (0, errno, "cannot read %s", CVSADM_UPROG);
- else
- error (0, 0, "unexpected end of file on %s", CVSADM_UPROG);
-
- if (fclose (fp) < 0)
- error (0, errno, "cannot close %s", CVSADM_UPROG);
- if (line != NULL)
- free (line);
- free (repository);
- }
-
if (strchr (dir, '/') == NULL)
{
/* FIXME: chdir ("..") loses with symlinks. */
@@ -1161,7 +1099,7 @@ isremoved (node, closure)
Node *node;
void *closure;
{
- Entnode *entdata = (Entnode*) node->data;
+ Entnode *entdata = node->data;
/* If the first character of the version is a '-', the file has been
removed. */
@@ -1173,7 +1111,7 @@ isremoved (node, closure)
and the directory doesn't exist, then just return 0. */
int
isemptydir (dir, might_not_exist)
- char *dir;
+ const char *dir;
int might_not_exist;
{
DIR *dirp;
@@ -1377,7 +1315,7 @@ VERS: ", 0);
{
revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL);
status = RCS_checkout (vers_ts->srcfile, (char *) NULL,
- vers_ts->vn_rcs, vers_ts->vn_tag,
+ vers_ts->vn_rcs, vers_ts->tag,
vers_ts->options, RUN_TTY,
checkout_to_buffer, revbuf);
}
@@ -1385,7 +1323,7 @@ VERS: ", 0);
#endif
status = RCS_checkout (vers_ts->srcfile,
pipeout ? NULL : finfo->file,
- vers_ts->vn_rcs, vers_ts->vn_tag,
+ vers_ts->vn_rcs, vers_ts->tag,
vers_ts->options, RUN_TTY,
(RCSCHECKOUTPROC) NULL, (void *) NULL);
}
@@ -1408,8 +1346,11 @@ VERS: ", 0);
is here only because noexec doesn't write srcfile->path
for us to stat. */
if (stat (vers_ts->srcfile->path, &sb) < 0)
+ {
+ buf_free (revbuf);
error (1, errno, "cannot stat %s",
vers_ts->srcfile->path);
+ }
mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
}
@@ -1515,6 +1456,8 @@ VERS: ", 0);
/* fix up the vers structure, in case it is used by join */
if (join_rev1)
{
+ /* FIXME: Throwing away the original revision info is almost
+ certainly wrong -- what if join_rev1 is "BASE"? */
if (vers_ts->vn_user != NULL)
free (vers_ts->vn_user);
if (vers_ts->vn_rcs != NULL)
@@ -1524,7 +1467,7 @@ VERS: ", 0);
}
/* If this is really Update and not Checkout, recode history */
- if (strcmp (command_name, "update") == 0)
+ if (strcmp (cvs_cmd_name, "update") == 0)
history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
finfo->repository);
@@ -1571,6 +1514,8 @@ VERS: ", 0);
free (backup);
}
+ if (revbuf != NULL)
+ buf_free (revbuf);
return (retval);
}
@@ -1717,8 +1662,20 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
data.final_nl = 0;
data.compute_checksum = 0;
+ /* FIXME - Passing vers_ts->tag here is wrong in the least number
+ * of cases. Since we don't know whether vn_user was checked out
+ * using a tag, we pass vers_ts->tag, which, assuming the user did
+ * not specify a new TAG to -r, will be the branch we are on.
+ *
+ * The only thing it is used for is to substitute in for the Name
+ * RCS keyword, so in the error case, the patch fails to apply on
+ * the client end and we end up resending the whole file.
+ *
+ * At least, if we are keeping track of the tag vn_user came from,
+ * I don't know where yet. -DRP
+ */
retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
- vers_ts->vn_user, (char *) NULL,
+ vers_ts->vn_user, vers_ts->tag,
vers_ts->options, RUN_TTY,
patch_file_write, (void *) &data);
@@ -1741,7 +1698,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
cvs_MD5Init (&data.context);
retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
- vers_ts->vn_rcs, vers_ts->vn_tag,
+ vers_ts->vn_rcs, vers_ts->tag,
vers_ts->options, RUN_TTY,
patch_file_write, (void *) &data);
@@ -1863,10 +1820,10 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
if (CVS_STAT (finfo->file, file_info) < 0)
error (1, errno, "could not stat %s", finfo->file);
- /* If this is really Update and not Checkout, recode history */
- if (strcmp (command_name, "update") == 0)
- history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
- finfo->repository);
+ /* If this is really Update and not Checkout, record history. */
+ if (strcmp (cvs_cmd_name, "update") == 0)
+ history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
+ finfo->file, finfo->repository);
freevers_ts (&xvers_ts);
@@ -1933,7 +1890,7 @@ patch_file_write (callerdat, buffer, len)
* Several of the types we process only print a bit of information consisting
* of a single letter and the name.
*/
-static void
+void
write_letter (finfo, letter)
struct file_info *finfo;
int letter;
@@ -1974,6 +1931,8 @@ write_letter (finfo, letter)
return;
}
+
+
/*
* Do all the magic associated with a file which needs to be merged
*/
@@ -2048,8 +2007,8 @@ merge_file (finfo, vers)
goto out;
}
- status = RCS_merge(finfo->rcs, vers->srcfile->path, finfo->file,
- vers->options, vers->vn_user, vers->vn_rcs);
+ status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
+ vers->options, vers->vn_user, vers->vn_rcs);
if (status != 0 && status != 1)
{
error (0, status == -1 ? errno : 0,
@@ -2085,6 +2044,8 @@ merge_file (finfo, vers)
/* fix up the vers structure, in case it is used by join */
if (join_rev1)
{
+ /* FIXME: Throwing away the original revision info is almost
+ certainly wrong -- what if join_rev1 is "BASE"? */
if (vers->vn_user != NULL)
free (vers->vn_user);
vers->vn_user = xstrdup (vers->vn_rcs);
@@ -2127,7 +2088,8 @@ merge_file (finfo, vers)
write_letter (finfo, 'C');
- history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
+ history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
+ finfo->repository);
}
else if (retcode == -1)
@@ -2147,9 +2109,23 @@ merge_file (finfo, vers)
return retval;
}
+
+
/*
* Do all the magic associated with a file which needs to be joined
- * (-j option)
+ * (reached via the -j option to checkout or update).
+ *
+ * INPUTS
+ * finfo File information about the destination file.
+ * vers The Vers_TS structure for finfo.
+ *
+ * GLOBALS
+ * join_rev1 From the command line.
+ * join_rev2 From the command line.
+ * server_active Natch.
+ *
+ * ASSUMPTIONS
+ * 1. Is not called in client mode.
*/
static void
join_file (finfo, vers)
@@ -2200,6 +2176,9 @@ join_file (finfo, vers)
jdate1 = NULL;
}
+ /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
+ below about vn_user. */
+
/* Convert the second revision, walking branches and dates. */
rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL);
@@ -2381,13 +2360,41 @@ join_file (finfo, vers)
return;
}
- /* If the target of the merge is the same as the working file
- revision, then there is nothing to do. */
- if (vers->vn_user != NULL && strcmp (rev2, vers->vn_user) == 0)
+ /* If the two merge revisions are the same, then there is nothing
+ * to do. This needs to be checked before the rev2 == up-to-date base
+ * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
+ * "already contains the changes between <rev1> and <rev1>" message.
+ */
+ if (rev1 && strcmp (rev1, rev2) == 0)
+ {
+ free (rev1);
+ free (rev2);
+ return;
+ }
+
+ /* If we know that the user file is up-to-date, then it becomes an
+ * optimization to skip the merge when rev2 is the same as the base
+ * revision. i.e. we know that diff3(file2,file1,file2) will produce
+ * file2.
+ */
+ if (vers->vn_user != NULL && vers->ts_user != NULL
+ && strcmp (vers->ts_user, vers->ts_rcs) == 0
+ && strcmp (rev2, vers->vn_user) == 0)
{
+ if (!really_quiet)
+ {
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (rev1 ? rev1 : "creation", 0);
+ cvs_output (" and ", 0);
+ cvs_output (rev2, 0);
+ cvs_output ("\n", 1);
+ }
+
if (rev1 != NULL)
free (rev1);
free (rev2);
+
return;
}
@@ -2442,17 +2449,8 @@ join_file (finfo, vers)
return;
}
- /* If the two merge revisions are the same, then there is nothing
- to do. */
- if (strcmp (rev1, rev2) == 0)
- {
- free (rev1);
- free (rev2);
- return;
- }
-
/* If there is no working file, then we can't do the merge. */
- if (vers->vn_user == NULL)
+ if (vers->vn_user == NULL || vers->vn_user[0] == '-')
{
free (rev1);
free (rev2);
@@ -2476,8 +2474,11 @@ join_file (finfo, vers)
{
int retcode;
/* The file is up to date. Need to check out the current contents. */
+ /* FIXME - see the FIXME comment above the call to RCS_checkout in the
+ * patch_file function.
+ */
retcode = RCS_checkout (vers->srcfile, finfo->file,
- vers->vn_user, (char *) NULL,
+ vers->vn_user, vers->tag,
(char *) NULL, RUN_TTY,
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
@@ -2523,16 +2524,29 @@ join_file (finfo, vers)
&& vers->ts_user != NULL
&& strcmp (vers->ts_user, vers->ts_rcs) == 0
- /* 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. */
+ /* Avoid this in the text file case. See below for why.
+ */
&& (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, t_options,
- RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
+ /* FIXME: Verify my comment below:
+ *
+ * RCS_merge does nothing with keywords. It merges the changes between
+ * two revisions without expanding the keywords (it might expand in
+ * -kk mode before computing the diff between rev1 and rev2 - I'm not
+ * sure). In other words, the keyword lines in the current work file
+ * get left alone.
+ *
+ * Therfore, checking out the destination revision (rev2) is probably
+ * incorrect in the text case since we should see the keywords that were
+ * substituted into the original file at the time it was checked out
+ * and not the keywords from rev2.
+ *
+ * Also, it is safe to pass in NULL for nametag since we know no
+ * substitution is happening during the binary mode checkout.
+ */
+ if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL, t_options,
+ RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0 )
status = 2;
else
status = 0;
@@ -2560,13 +2574,14 @@ join_file (finfo, vers)
|| special_file_mismatch (finfo, rev1, rev2))
{
/* We are dealing with binary files, or files with a
- permission/linkage mismatch, and real merging would
+ permission/linkage mismatch (this second case only occurs when
+ PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
need to take place. This is a conflict. We give the user
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, t_options,
- RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
+ if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL,
+ t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
status = 2;
else
status = 0;
@@ -2598,16 +2613,39 @@ join_file (finfo, vers)
status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
t_options, rev1, rev2);
- if (status != 0 && status != 1)
+ if (status != 0)
{
- error (0, status == -1 ? errno : 0,
- "could not merge revision %s of %s", rev2, finfo->fullname);
- error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
- finfo->fullname, backup);
- rename_file (backup, finfo->file);
+ if (status != 1)
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", rev2, finfo->fullname);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ finfo->fullname, backup);
+ rename_file (backup, finfo->file);
+ }
+ }
+ else /* status == 0 */
+ {
+ /* FIXME: the noexec case is broken. RCS_merge could be doing the
+ xcmp on the temporary files without much hassle, I think. */
+ if (!noexec && !xcmp (backup, finfo->file))
+ {
+ if (!really_quiet)
+ {
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (rev1, 0);
+ cvs_output (" and ", 0);
+ cvs_output (rev2, 0);
+ cvs_output ("\n", 1);
+ }
+
+ /* and skip the registering and sending the new file since it
+ * hasn't been updated.
+ */
+ goto out;
+ }
}
- free (rev1);
- free (rev2);
/* The file has changed, but if we just checked it out it may
still have the same timestamp it did when it was first
@@ -2644,9 +2682,15 @@ join_file (finfo, vers)
(struct buffer *) NULL);
}
#endif
+
+out:
+ free (rev1);
+ free (rev2);
free (backup);
}
+
+
/*
* Report whether revisions REV1 and REV2 of FINFO agree on:
* . file ownership
@@ -2726,7 +2770,7 @@ special_file_mismatch (finfo, rev1, rev2)
else
{
n = findnode (finfo->rcs->versions, rev1);
- vp = (RCSVers *) n->data;
+ vp = n->data;
n = findnode (vp->other_delta, "symlink");
if (n != NULL)
@@ -2761,7 +2805,7 @@ special_file_mismatch (finfo, rev1, rev2)
if (sscanf (n->data, "%15s %lu", ftype,
&dev_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
- finfo->file, rev1, n->data);
+ finfo->file, rev1, (char *)n->data);
rev1_dev = dev_long;
if (strcmp (ftype, "character") == 0)
rev1_mode |= S_IFCHR;
@@ -2804,7 +2848,7 @@ special_file_mismatch (finfo, rev1, rev2)
else
{
n = findnode (finfo->rcs->versions, rev2);
- vp = (RCSVers *) n->data;
+ vp = n->data;
n = findnode (vp->other_delta, "symlink");
if (n != NULL)
@@ -2839,7 +2883,7 @@ special_file_mismatch (finfo, rev1, rev2)
if (sscanf (n->data, "%15s %lu", ftype,
&dev_long) < 2)
error (1, 0, "%s:%s has bad `special' newphrase %s",
- finfo->file, rev2, n->data);
+ finfo->file, rev2, (char *)n->data);
rev2_dev = dev_long;
if (strcmp (ftype, "character") == 0)
rev2_mode |= S_IFCHR;
diff --git a/contrib/cvs/src/update.h b/contrib/cvs/src/update.h
index 1c3ea66..c886b4c 100644
--- a/contrib/cvs/src/update.h
+++ b/contrib/cvs/src/update.h
@@ -18,6 +18,6 @@ int do_update PROTO((int argc, char *argv[], char *xoptions, char *xtag,
char *xdate, int xforce, int local, int xbuild,
int xaflag, int xprune, int xpipeout, int which,
char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir,
- int xpull_template));
+ int xpull_template, char *repository));
int joining PROTO((void));
-extern int isemptydir PROTO ((char *dir, int might_not_exist));
+extern int isemptydir PROTO ((const char *dir, int might_not_exist));
OpenPOWER on IntegriCloud