Initial merge of cvs-1.11.5 -> 1.11.15 changes onto mainline

This commit is contained in:
Peter Wemm 2004-04-15 01:17:28 +00:00
parent edc4a449d1
commit 25773c5448
25 changed files with 3256 additions and 2931 deletions

View File

@ -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

View 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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 *));

View File

@ -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;
}

View File

@ -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;

View File

@ -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
*/

View File

@ -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)

View File

@ -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");

View File

@ -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",

View File

@ -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);

View File

@ -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 ();

View File

@ -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;
}

View File

@ -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

View File

@ -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 *));

View 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;

View File

@ -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

View File

@ -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;

View File

@ -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));