Initial merge of cvs-1.11.5 -> 1.11.15 changes onto mainline
This commit is contained in:
parent
edc4a449d1
commit
25773c5448
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
{
|
||||
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. */
|
||||
/* 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 (! 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);
|
||||
if (!isabsolute (where) && 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);
|
||||
|
||||
#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)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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 *));
|
||||
|
@ -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)
|
||||
empty_file = diff_file_nodiff( finfo, vers, empty_file, &rev1_cache );
|
||||
if( empty_file == DIFF_SAME )
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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?). */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 *));
|
||||
|
@ -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)
|
||||
|
||||
if (rev1_cache != NULL)
|
||||
use_file1 = rev1_cache;
|
||||
else
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user