Merge cyclic changes for 1.10.7 only our mainline.

This commit is contained in:
Peter Wemm 1999-12-11 12:50:10 +00:00
parent c17d50044b
commit 9bd45385bc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=54431
15 changed files with 1973 additions and 663 deletions

View File

@ -50,7 +50,6 @@ static int precommit_list_proc PROTO((Node * p, void *closure));
static int precommit_proc PROTO((char *repository, char *filter));
static int remove_file PROTO ((struct file_info *finfo, char *tag,
char *message));
static void fix_rcs_modes PROTO((char *rcs, char *user));
static void fixaddfile PROTO((char *file, char *repository));
static void fixbranch PROTO((RCSNode *, char *branch));
static void unlockrcs PROTO((RCSNode *rcs));
@ -342,10 +341,11 @@ commit (argc, argv)
readonly user stuff (CVSROOT/readers, &c). That is, why should
root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
if (geteuid () == (uid_t) 0
#ifdef CLIENT_SUPPORT
# ifdef CLIENT_SUPPORT
/* Who we are on the client side doesn't affect logging. */
&& !client_active
#endif
)
# endif
)
{
struct passwd *pw;
@ -411,7 +411,7 @@ commit (argc, argv)
argv += optind;
/* numeric specified revision means we ignore sticky tags... */
if (saved_tag && isdigit (*saved_tag))
if (saved_tag && isdigit ((unsigned char) *saved_tag))
{
aflag = 1;
/* strip trailing dots */
@ -566,13 +566,6 @@ commit (argc, argv)
send_arg("-n");
option_with_arg ("-r", saved_tag);
/* Sending only the names of the files which were modified, added,
or removed means that the server will only do an up-to-date
check on those files. This is different from local CVS and
previous versions of client/server CVS, but it probably is a Good
Thing, or at least Not Such A Bad Thing. */
send_file_names (find_args.argc, find_args.argv, 0);
/* FIXME: This whole find_args.force/SEND_FORCE business is a
kludge. It would seem to be a server bug that we have to
say that files are modified when they are not. This makes
@ -585,6 +578,13 @@ commit (argc, argv)
send_files (find_args.argc, find_args.argv, local, 0,
find_args.force ? SEND_FORCE : 0);
/* Sending only the names of the files which were modified, added,
or removed means that the server will only do an up-to-date
check on those files. This is different from local CVS and
previous versions of client/server CVS, but it probably is a Good
Thing, or at least Not Such A Bad Thing. */
send_file_names (find_args.argc, find_args.argv, 0);
send_to_server ("ci\012", 0);
err = get_responses_and_close ();
if (err != 0 && use_editor && saved_message != NULL)
@ -677,9 +677,10 @@ commit (argc, argv)
{
time_t now;
(void) time (&now);
if (now == last_register_time)
for (;;)
{
(void) time (&now);
if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
}
}
@ -708,7 +709,7 @@ classify_file_internal (finfo, vers)
noexec = quiet = really_quiet = 1;
/* handle specified numeric revision specially */
if (saved_tag && isdigit (*saved_tag))
if (saved_tag && isdigit ((unsigned char) *saved_tag))
{
/* If the tag is for the trunk, make sure we're at the head */
if (numdots (saved_tag) < 2)
@ -792,6 +793,19 @@ check_fileproc (callerdat, finfo)
struct commit_info *ci;
struct logfile_info *li;
size_t cvsroot_len = strlen (CVSroot_directory);
if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0
&& ISDIRSEP (finfo->repository[cvsroot_len])
&& strncmp (finfo->repository + cvsroot_len + 1,
CVSROOTADM,
sizeof (CVSROOTADM) - 1) == 0
&& ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
&& strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
CVSNULLREPOS) == 0
)
error (1, 0, "cannot check in to %s", finfo->repository);
status = classify_file_internal (finfo, &vers);
/*
@ -830,7 +844,7 @@ check_fileproc (callerdat, finfo)
* allow the commit if timestamp is identical or if we find
* an RCS_MERGE_PAT in the file.
*/
if (!saved_tag || !isdigit (*saved_tag))
if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
{
if (vers->date)
{
@ -902,7 +916,9 @@ warning: file `%s' seems to still contain conflict indicators",
}
}
if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
if (status == T_REMOVED
&& vers->tag
&& isdigit ((unsigned char) *vers->tag))
{
/* Remove also tries to forbid this, but we should check
here. I'm only _sure_ about somewhat obscure cases
@ -941,7 +957,7 @@ warning: file `%s' seems to still contain conflict indicators",
}
free (rcs);
}
if (vers->tag && isdigit (*vers->tag) &&
if (vers->tag && isdigit ((unsigned char) *vers->tag) &&
numdots (vers->tag) > 1)
{
error (0, 0,
@ -1001,7 +1017,7 @@ warning: file `%s' seems to still contain conflict indicators",
ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
ci->status = status;
if (vers->tag)
if (isdigit (*vers->tag))
if (isdigit ((unsigned char) *vers->tag))
ci->rev = xstrdup (vers->tag);
else
ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
@ -1120,7 +1136,7 @@ precommit_proc (repository, filter)
s = xstrdup (filter);
for (cp = s; *cp; cp++)
if (isspace (*cp))
if (isspace ((unsigned char) *cp))
{
*cp = '\0';
break;
@ -1267,7 +1283,11 @@ commit_fileproc (callerdat, finfo)
Since the branch test was done in check_fileproc for
modified files, we need to stub it in again here. */
if (ci->tag)
if (ci->tag
/* If numeric, it is on the trunk; check_fileproc enforced
this. */
&& !isdigit ((unsigned char) ci->tag[0]))
{
if (finfo->rcs == NULL)
error (1, 0, "internal error: no parsed RCS file");
@ -1601,16 +1621,16 @@ findmaxrev (p, closure)
* XXX - if removing a ,v file that is a relative symbolic link to
* another ,v file, we probably should add a ".." component to the
* link to keep it relative after we move it into the attic.
*/
Return value is 0 on success, or >0 on error (in which case we have
printed an error message). */
static int
remove_file (finfo, tag, message)
struct file_info *finfo;
char *tag;
char *message;
{
mode_t omask;
int retcode;
char *tmp;
int branch;
int lockflag;
@ -1700,16 +1720,6 @@ remove_file (finfo, tag, message)
RCS_rewrite (finfo->rcs, NULL, NULL);
}
#ifdef SERVER_SUPPORT
if (server_active) {
/* If this is the server, there will be a file sitting in the
temp directory which is the kludgy way in which server.c
tells time_stamp that the file is no longer around. Remove
it so we can create temp files with that name (ignore errors). */
unlink_file (finfo->file);
}
#endif
/* check something out. Generally this is the head. If we have a
particular rev, then name it. */
retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
@ -1746,34 +1756,9 @@ remove_file (finfo, tag, message)
if (rev != NULL)
free (rev);
old_path = finfo->rcs->path;
old_path = xstrdup (finfo->rcs->path);
if (!branch)
{
/* this was the head; really move it into the Attic */
tmp = xmalloc(strlen(finfo->repository) +
sizeof('/') +
sizeof(CVSATTIC) +
sizeof('/') +
strlen(finfo->file) +
sizeof(RCSEXT) + 1);
(void) sprintf (tmp, "%s/%s", finfo->repository, CVSATTIC);
omask = umask (cvsumask);
(void) CVS_MKDIR (tmp, 0777);
(void) umask (omask);
(void) sprintf (tmp, "%s/%s/%s%s", finfo->repository, CVSATTIC,
finfo->file, RCSEXT);
if (strcmp (finfo->rcs->path, tmp) != 0
&& CVS_RENAME (finfo->rcs->path, tmp) == -1
&& (isreadable (finfo->rcs->path) || !isreadable (tmp)))
{
free(tmp);
return (1);
}
/* The old value of finfo->rcs->path is in old_path, and is
freed below. */
finfo->rcs->path = tmp;
}
RCS_setattic (finfo->rcs, 1);
/* Print message that file was removed. */
cvs_output (old_path, 0);
@ -1784,8 +1769,7 @@ remove_file (finfo, tag, message)
cvs_output ("\ndone\n", 0);
free(prev_rev);
if (old_path != finfo->rcs->path)
free (old_path);
free (old_path);
Scratch_Entry (finfo->entries, finfo->file);
return (0);
@ -1811,7 +1795,9 @@ finaladd (finfo, rev, tag, options)
char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
+ sizeof (CVSEXT_LOG) + 10);
(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
(void) unlink_file (tmp);
if (unlink_file (tmp) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", tmp);
free (tmp);
}
else
@ -1855,7 +1841,10 @@ fixaddfile (file, repository)
save_really_quiet = really_quiet;
really_quiet = 1;
if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
(void) unlink_file (rcs);
{
if (unlink_file (rcs) < 0)
error (0, errno, "cannot remove %s", rcs);
}
else
freercsnode (&rcsfile);
really_quiet = save_really_quiet;
@ -1902,8 +1891,20 @@ checkaddfile (file, repository, tag, options, rcsnode)
int newfile = 0;
RCSNode *rcsfile = NULL;
int retval;
int adding_on_branch;
if (tag)
/* Callers expect to be able to use either "" or NULL to mean the
default keyword expansion. */
if (options != NULL && options[0] == '\0')
options = NULL;
if (options != NULL)
assert (options[0] == '-' && options[1] == 'k');
/* If numeric, it is on the trunk; check_fileproc enforced
this. */
adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
if (adding_on_branch)
{
rcs = xmalloc (strlen (repository) + strlen (file)
+ sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
@ -1926,6 +1927,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
/* file has existed in the past. Prepare to resurrect. */
char *rev;
char *oldexpand;
if ((rcsfile = *rcsnode) == NULL)
{
@ -1934,41 +1936,38 @@ checkaddfile (file, repository, tag, options, rcsnode)
goto out;
}
if (tag == NULL)
oldexpand = RCS_getexpand (rcsfile);
if ((oldexpand != NULL
&& options != NULL
&& strcmp (options + 2, oldexpand) != 0)
|| (oldexpand == NULL && options != NULL))
{
char *oldfile;
/* We tell the user about this, because it means that the
old revisions will no longer retrieve the way that they
used to. */
error (0, 0, "changing keyword expansion mode to %s", options);
RCS_setexpand (rcsfile, options + 2);
}
/* we are adding on the trunk, so move the file out of the
Attic. */
oldfile = xstrdup (rcs);
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
if (strcmp (oldfile, rcs) == 0)
if (!adding_on_branch)
{
/* We are adding on the trunk, so move the file out of the
Attic. */
if (!(rcsfile->flags & INATTIC))
{
error (0, 0, "internal error: confused about attic for %s",
oldfile);
out1:
free (oldfile);
rcsfile->path);
retval = 1;
goto out;
}
if (CVS_RENAME (oldfile, rcs) != 0)
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
if (RCS_setattic (rcsfile, 0))
{
error (0, errno, "failed to move `%s' out of the attic",
oldfile);
goto out1;
retval = 1;
goto out;
}
if (isreadable (oldfile)
|| !isreadable (rcs))
{
error (0, 0, "\
internal error: `%s' didn't move out of the attic",
oldfile);
goto out1;
}
free (oldfile);
free (rcsfile->path);
rcsfile->path = xstrdup (rcs);
}
rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
@ -2021,7 +2020,7 @@ internal error: `%s' didn't move out of the attic",
}
/* Set RCS keyword expansion options. */
if (options && options[0] == '-' && options[1] == 'k')
if (options != NULL)
opt = options + 2;
else
opt = NULL;
@ -2050,7 +2049,7 @@ internal error: `%s' didn't move out of the attic",
/* when adding a file for the first time, and using a tag, we need
to create a dead revision on the trunk. */
if (tag && newfile)
if (adding_on_branch && newfile)
{
char *tmp;
FILE *fp;
@ -2112,7 +2111,7 @@ internal error: `%s' didn't move out of the attic",
}
}
if (tag != NULL)
if (adding_on_branch)
{
/* when adding with a tag, we need to stub a branch, if it
doesn't already exist. */
@ -2178,13 +2177,22 @@ internal error: `%s' didn't move out of the attic",
fileattr_newfile (file);
/* I don't think fix_rcs_modes is needed any more. In the
add_rcs_file case, the algorithms used by add_rcs_file and
fix_rcs_modes are the same, so there is no need to go through
it all twice. In the other cases, I think we want to just
preserve the mode that the file had before we started. That is
a behavior change, but I would think a desirable one. */
fix_rcs_modes (rcs, file);
/* At this point, we used to set the file mode of the RCS file
based on the mode of the file in the working directory. If we
are creating the RCS file for the first time, add_rcs_file does
this already. If we are re-adding the file, then perhaps it is
consistent to preserve the old file mode, just as we preserve
the old keyword expansion mode.
If we decide that we should change the modes, then we can't do
it here anyhow. At this point, the RCS file may be owned by
somebody else, so a chmod will fail. We need to instead do the
chmod after rewriting it.
FIXME: In general, I think the file mode (and the keyword
expansion mode) should be associated with a particular revision
of the file, so that it is possible to have different revisions
of a file have different modes. */
retval = 0;
@ -2218,7 +2226,8 @@ lock_RCS (user, rcs, rev, repository)
* the head points to the trunk, not a branch... and as such, it's not
* necessary to move the head in this case.
*/
if (rev == NULL || (rev && isdigit (*rev) && numdots (rev) < 2))
if (rev == NULL
|| (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
{
branch = xstrdup (rcs->branch);
if (branch != NULL)
@ -2275,69 +2284,6 @@ lock_RCS (user, rcs, rev, repository)
return (1);
}
/* Called when "add"ing files to the RCS respository. It doesn't seem to
be possible to get RCS to use the right mode, so we change it after
the fact. TODO: now that RCS has been librarified, we have the power
to change this. */
static void
fix_rcs_modes (rcs, user)
char *rcs;
char *user;
{
struct stat sb;
mode_t rcs_mode;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
/* Do ye nothing to the modes on a symbolic link. */
if (preserve_perms && islink (user))
return;
#endif
if (CVS_STAT (user, &sb) < 0)
{
/* FIXME: Should be ->fullname. */
error (0, errno, "warning: cannot stat %s", user);
return;
}
/* Now we compute the new mode.
TODO: decide whether this whole thing can/should be skipped
when `preserve_perms' is set. Almost certainly so. -twp
The algorithm that we use is:
Write permission is always off (this is what RCS and CVS have always
done).
If S_IRUSR is on (user read), then the read permission of
the RCS file will be on. It would seem that if this is off,
then other users can't do "cvs update" and such, so perhaps this
should be hardcoded to being on (it is a strange case, though--the
case in which a user file doesn't have user read permission on).
If S_IXUSR is on (user execute), then set execute permission
on the RCS file. This allows other users who check out the file
to get the right setting for whether a shell script (for example)
has the executable bit set.
The result of that calculation is modified by CVSUMASK. The
reason, of course, that the read and execute settings take the
user bit and copy it to all three bits (user, group, other), is
that it should be CVSUMASK, not the umask of individual users,
which is the sole determiner of modes in the repository. */
rcs_mode = 0;
if (sb.st_mode & S_IRUSR)
rcs_mode |= S_IRUSR | S_IRGRP | S_IROTH;
if (sb.st_mode & S_IXUSR)
rcs_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
rcs_mode &= ~cvsumask;
if (chmod (rcs, rcs_mode) < 0)
error (0, errno, "warning: cannot change mode of %s", rcs);
}
/*
* free an UPDATE node's data
*/

View File

@ -9,6 +9,7 @@
/*
* basic information used in all source files
*
* $FreeBSD$
*/
@ -371,11 +372,16 @@ extern char *RCS_citag;
/* Access method specified in CVSroot. */
typedef enum {
local_method, server_method, pserver_method, kserver_method, gserver_method,
ext_method
ext_method, fork_method
} CVSmethod;
extern char *method_names[]; /* change this in root.c if you change
the enum above */
/* This global variable holds the global -d option. It is NULL if -d
was not used, which means that we must get the CVSroot information
from the CVSROOT environment variable or from a CVS/Root file. */
extern char *CVSroot_cmdline;
extern char *CVSroot_original; /* the active, complete CVSroot string */
extern int client_active; /* nonzero if we are doing remote access */
extern CVSmethod CVSroot_method; /* one of the enum values above */
@ -383,6 +389,11 @@ extern char *CVSroot_username; /* the username or NULL if method == local */
extern char *CVSroot_hostname; /* the hostname or NULL if method == local */
extern char *CVSroot_directory; /* the directory name */
/* These variables keep track of all of the CVSROOT directories that
have been seen by the client and the current one of those selected. */
extern List *root_directories;
extern char *current_root;
extern char *emptydir_name PROTO ((void));
extern int trace; /* Show all commands */
@ -393,11 +404,11 @@ extern int require_real_user; /* skip CVSROOT/passwd, /etc/passwd users only*/
extern int top_level_admin;
#ifdef AUTH_SERVER_SUPPORT
extern char *Pserver_Repos; /* used to check that same repos is
transmitted in pserver auth and in
CVS protocol. */
#endif /* AUTH_SERVER_SUPPORT */
#ifdef CLIENT_SUPPORT
extern List *dirs_sent_to_server; /* used to decide which "Argument
xxx" commands to send to each
server in multiroot mode. */
#endif
extern char hostname[];
@ -438,6 +449,7 @@ void Subdir_Deregister PROTO((List *, const char *, const char *));
char *Make_Date PROTO((char *rawdate));
char *date_from_time_t PROTO ((time_t));
void date_to_internet PROTO ((char *, char *));
char *Name_Repository PROTO((char *dir, char *update_dir));
char *Short_Repository PROTO((char *repository));
@ -456,7 +468,7 @@ extern void check_numeric PROTO ((const char *, int, char **));
char *getcaller PROTO((void));
char *time_stamp PROTO((char *file));
char *xmalloc PROTO((size_t bytes));
void *xmalloc PROTO((size_t bytes));
void *xrealloc PROTO((void *ptr, size_t bytes));
void expand_string PROTO ((char **, size_t *, size_t));
char *xstrdup PROTO((const char *str));
@ -509,6 +521,9 @@ void lock_tree_for_write PROTO ((int argc, char **argv, int local, int aflag));
/* See lock.c for description. */
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 ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
@ -635,6 +650,7 @@ char *make_message_rcslegal PROTO((char *message));
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 *));
extern void resolve_symlink PROTO ((char **filename));
/* flags for run_exec(), the fast system() for CVS */
#define RUN_NORMAL 0x0000 /* no special behaviour */
@ -655,7 +671,6 @@ int run_exec PROTO((const char *stin, const char *stout, const char *sterr,
FILE *run_popen PROTO((const char *, const char *));
int piped_child PROTO((char **, int *, int *));
void close_on_exec PROTO((int));
int filter_stream_through_program PROTO((int, int, char **, pid_t *));
pid_t waitpid PROTO((pid_t, int *, int));

View File

@ -12,6 +12,8 @@
*
* Without any file arguments, runs diff against all the currently modified
* files.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -40,7 +42,13 @@ static enum diff_file diff_file_nodiff PROTO ((struct file_info *finfo,
static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static void diff_mark_errors PROTO((int err));
/* Global variables. Would be cleaner if we just put this stuff in a
struct like log.c does. */
/* Command line tags, from -r option. Points into argv. */
static char *diff_rev1, *diff_rev2;
/* Command line dates, from -D option. Malloc'd. */
static char *diff_date1, *diff_date2;
static char *use_rev1, *use_rev2;
static int have_rev1_label, have_rev2_label;
@ -224,15 +232,19 @@ diff (argc, argv)
* non-recursive/recursive diff.
*/
/* For server, need to be able to do this command more than once
(according to the protocol spec, even if the current client
doesn't use it). */
/* Clean out our global variables (multiroot can call us multiple
times and the server can too, if the client sends several
diff commands). */
if (opts == NULL)
{
opts_allocated = 1;
opts = xmalloc (opts_allocated);
}
opts[0] = '\0';
diff_rev1 = NULL;
diff_rev2 = NULL;
diff_date1 = NULL;
diff_date2 = NULL;
optind = 0;
while ((c = getopt_long (argc, argv,
@ -267,7 +279,7 @@ diff (argc, argv)
break;
case 131:
/* --ifdef. */
strcat_and_allocate (&opts, &opts_allocated, " -D");
strcat_and_allocate (&opts, &opts_allocated, " --ifdef=");
strcat_and_allocate (&opts, &opts_allocated, optarg);
break;
case 129: case 130: case 132: case 133: case 134:
@ -353,17 +365,18 @@ diff (argc, argv)
if (diff_date2)
client_senddate (diff_date2);
send_file_names (argc, argv, SEND_EXPAND_WILD);
/* Send the current files unless diffing two revs from the archive */
if (diff_rev2 == NULL && diff_date2 == NULL)
send_files (argc, argv, local, 0, 0);
else
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("diff\012", 0);
err = get_responses_and_close ();
free (options);
options = NULL;
return (err);
}
#endif
@ -386,6 +399,13 @@ diff (argc, argv)
/* clean up */
free (options);
options = NULL;
if (diff_date1 != NULL)
free (diff_date1);
if (diff_date2 != NULL)
free (diff_date2);
return (err);
}

View File

@ -17,6 +17,10 @@
definitions under operating systems (like, say, Windows NT) with different
file system semantics. */
/*
* $FreeBSD$
*/
#include "cvs.h"
static int deep_remove_dir PROTO((const char *path));
@ -34,12 +38,8 @@ copy_file (from, to)
int fdin, fdout;
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
#endif
(void) fprintf (stderr, "%s-> copy(%s,%s)\n",
CLIENT_SERVER_STR, from, to);
if (noexec)
return;
@ -377,14 +377,9 @@ xchmod (fname, writable)
}
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
(server_active) ? 'S' : ' ', fname,
(void) fprintf (stderr, "%s-> chmod(%s,%o)\n",
CLIENT_SERVER_STR, fname,
(unsigned int) mode);
#else
(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
(unsigned int) mode);
#endif
if (noexec)
return;
@ -401,12 +396,8 @@ rename_file (from, to)
const char *to;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
#endif
(void) fprintf (stderr, "%s-> rename(%s,%s)\n",
CLIENT_SERVER_STR, from, to);
if (noexec)
return;
@ -422,12 +413,8 @@ unlink_file (f)
const char *f;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink(%s)\n",
(server_active) ? 'S' : ' ', f);
#else
(void) fprintf (stderr, "-> unlink(%s)\n", f);
#endif
(void) fprintf (stderr, "%s-> unlink(%s)\n",
CLIENT_SERVER_STR, f);
if (noexec)
return (0);
@ -506,6 +493,7 @@ deep_remove_dir (path)
*/
return -1;
errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
char *buf;
@ -539,6 +527,15 @@ deep_remove_dir (path)
}
}
free (buf);
errno = 0;
}
if (errno != 0)
{
int save_errno = errno;
closedir (dirp);
errno = save_errno;
return -1;
}
closedir (dirp);
return rmdir (path);

View File

@ -14,6 +14,8 @@
* VendorReleTag Tag for this particular release
*
* Additional arguments specify more Vendor Release Tags.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -94,6 +96,17 @@ import (argc, argv)
command_name);
break;
case 'd':
#ifdef SERVER_SUPPORT
if (server_active)
{
/* CVS 1.10 and older clients will send this, but it
doesn't do any good. So tell the user we can't
cope, rather than silently losing. */
error (0, 0,
"warning: not setting the time of import from the file");
error (0, 0, "due to client limitations");
}
#endif
use_file_modtime = 1;
break;
case 'b':
@ -132,6 +145,20 @@ import (argc, argv)
if (argc < 3)
usage (import_usage);
#ifdef SERVER_SUPPORT
/* This is for handling the Checkin-time request. It might seem a
bit odd to enable the use_file_modtime code even in the case
where Checkin-time was not sent for a particular file. The
effect is that we use the time of upload, rather than the time
when we call RCS_checkin. Since those times are both during
CVS's run, that seems OK, and it is easier to implement than
putting the "was Checkin-time sent" flag in CVS/Entries or some
such place. */
if (server_active)
use_file_modtime = 1;
#endif
for (i = 1; i < argc; i++) /* check the tags for validity */
{
int j;
@ -143,7 +170,8 @@ import (argc, argv)
}
/* XXX - this should be a module, not just a pathname */
if (! isabsolute (argv[0]))
if (! isabsolute (argv[0])
&& pathname_levels (argv[0]) == 0)
{
if (CVSroot_directory == NULL)
{
@ -158,9 +186,11 @@ import (argc, argv)
}
else
{
repository = xmalloc (strlen (argv[0]) + 5);
(void) strcpy (repository, argv[0]);
repos_len = 0;
/* It is somewhere between a security hole and "unexpected" to
let the client start mucking around outside the cvsroot
(wouldn't get the right CVSROOT configuration, &c). */
error (1, 0, "directory %s not relative within the repository",
argv[0]);
}
/*
@ -170,7 +200,7 @@ import (argc, argv)
* must only have two dots in it (like "1.1.1").
*/
for (cp = vbranch; *cp != '\0'; cp++)
if (!isdigit (*cp) && *cp != '.')
if (!isdigit ((unsigned char) *cp) && *cp != '.')
error (1, 0, "%s is not a numeric branch", vbranch);
if (numdots (vbranch) != 2)
error (1, 0, "Only branches with two dots are supported: %s", vbranch);
@ -212,9 +242,6 @@ import (argc, argv)
{
int err;
if (use_file_modtime)
send_arg("-d");
if (vbranch[0] != '\0')
option_with_arg ("-b", vbranch);
if (message)
@ -275,29 +302,52 @@ import (argc, argv)
{
if (!really_quiet)
{
char buf[80];
sprintf (buf, "\n%d conflicts created by this import.\n",
conflicts);
cvs_output (buf, 0);
cvs_output ("Use the following command to help the merge:\n\n",
0);
cvs_output ("\t", 1);
cvs_output (program_name, 0);
cvs_output (" checkout -j", 0);
cvs_output (argv[1], 0);
cvs_output (":yesterday -j", 0);
cvs_output (argv[1], 0);
cvs_output (" ", 1);
cvs_output (argv[0], 0);
cvs_output ("\n\n", 0);
char buf[20];
char *buf2;
cvs_output_tagged ("+importmergecmd", NULL);
cvs_output_tagged ("newline", NULL);
sprintf (buf, "%d", conflicts);
cvs_output_tagged ("conflicts", buf);
cvs_output_tagged ("text", " conflicts created by this import.");
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("text",
"Use the following command to help the merge:");
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("text", "\t");
cvs_output_tagged ("text", program_name);
if (CVSroot_cmdline != NULL)
{
cvs_output_tagged ("text", " -d ");
cvs_output_tagged ("text", CVSroot_cmdline);
}
cvs_output_tagged ("text", " checkout -j");
buf2 = xmalloc (strlen (argv[1]) + 20);
sprintf (buf2, "%s:yesterday", argv[1]);
cvs_output_tagged ("mergetag1", buf2);
free (buf2);
cvs_output_tagged ("text", " -j");
cvs_output_tagged ("mergetag2", argv[1]);
cvs_output_tagged ("text", " ");
cvs_output_tagged ("repository", argv[0]);
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("-importmergecmd", NULL);
}
/* FIXME: I'm not sure whether we need to put this information
into the loginfo. If we do, then note that it does not
report any required -d option. There is no particularly
clean way to tell the server about the -d option used by
the client. */
(void) fprintf (logfp, "\n%d conflicts created by this import.\n",
conflicts);
(void) fprintf (logfp,
"Use the following command to help the merge:\n\n");
(void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
program_name, argv[1], argv[1], argv[0]);
(void) fprintf (logfp, "\t%s checkout ", program_name);
(void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
argv[1], argv[1], argv[0]);
}
else
{
@ -340,9 +390,9 @@ import (argc, argv)
return (err);
}
/*
* process all the files in ".", then descend into other directories.
*/
/* Process all the files in ".", then descend into other directories.
Returns 0 for success, or >0 on error (in which case a message
will have been printed). */
static int
import_descend (message, vtag, targc, targv)
char *message;
@ -361,25 +411,27 @@ import_descend (message, vtag, targc, targv)
if ((dirp = CVS_OPENDIR (".")) == NULL)
{
error (0, errno, "cannot open directory");
err++;
}
else
{
errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
continue;
goto one_more_time_boys;
#ifdef SERVER_SUPPORT
/* CVS directories are created in the temp directory by
server.c because it doesn't special-case import. So
don't print a message about them, regardless of -I!. */
if (server_active && strcmp (dp->d_name, CVSADM) == 0)
continue;
goto one_more_time_boys;
#endif
if (ign_name (dp->d_name))
{
add_log ('I', dp->d_name);
continue;
goto one_more_time_boys;
}
if (
@ -418,12 +470,20 @@ import_descend (message, vtag, targc, targv)
vtag, targc, targv,
repository,
keyword_opt != NULL &&
keyword_opt[0] == 'b');
keyword_opt[0] == 'b',
use_file_modtime);
else
#endif
err += process_import_file (message, dp->d_name,
vtag, targc, targv);
}
one_more_time_boys:
errno = 0;
}
if (errno != 0)
{
error (0, errno, "cannot read directory");
++err;
}
(void) closedir (dirp);
}
@ -874,7 +934,7 @@ get_comment (user)
*/
(void) strcpy (suffix_path, cp);
for (cp = suffix_path; *cp; cp++)
if (isupper (*cp))
if (isupper ((unsigned char) *cp))
*cp = tolower (*cp);
suffix = suffix_path;
}

View File

@ -8,6 +8,8 @@
* Set Lock
*
* Lock file support for CVS.
*
* $FreeBSD$
*/
/* The node Concurrency in doc/cvs.texinfo has a brief introduction to
@ -73,6 +75,7 @@
unneeded complication although it presumably would be faster). */
#include "cvs.h"
#include <assert.h>
struct lock {
/* This is the directory in which we may have a lock named by the
@ -134,12 +137,161 @@ static List *lock_tree_list;
static char *locked_dir;
static List *locked_list;
/* LockDir from CVSROOT/config. */
char *lock_dir;
static char *lock_name PROTO ((char *repository, char *name));
/* Return a newly malloc'd string containing the name of the lock for the
repository REPOSITORY and the lock file name within that directory
NAME. Also create the directories in which to put the lock file
if needed (if we need to, could save system call(s) by doing
that only if the actual operation fails. But for now we'll keep
things simple). */
static char *
lock_name (repository, name)
char *repository;
char *name;
{
char *retval;
char *p;
char *q;
char *short_repos;
mode_t save_umask;
int saved_umask = 0;
if (lock_dir == NULL)
{
/* This is the easy case. Because the lock files go directly
in the repository, no need to create directories or anything. */
retval = xmalloc (strlen (repository) + strlen (name) + 10);
(void) sprintf (retval, "%s/%s", repository, name);
}
else
{
struct stat sb;
mode_t new_mode = 0;
/* The interesting part of the repository is the part relative
to CVSROOT. */
assert (CVSroot_directory != NULL);
assert (strncmp (repository, CVSroot_directory,
strlen (CVSroot_directory)) == 0);
short_repos = repository + strlen (CVSroot_directory);
assert (*short_repos++ == '/');
retval = xmalloc (strlen (lock_dir)
+ strlen (short_repos)
+ strlen (name)
+ 10);
strcpy (retval, lock_dir);
q = retval + strlen (retval);
*q++ = '/';
strcpy (q, short_repos);
/* In the common case, where the directory already exists, let's
keep it to one system call. */
if (CVS_STAT (retval, &sb) < 0)
{
/* If we need to be creating more than one directory, we'll
get the existence_error here. */
if (!existence_error (errno))
error (1, errno, "cannot stat directory %s", retval);
}
else
{
if (S_ISDIR (sb.st_mode))
goto created;
else
error (1, 0, "%s is not a directory", retval);
}
/* Now add the directories one at a time, so we can create
them if needed.
The idea behind the new_mode stuff is that the directory we
end up creating will inherit permissions from its parent
directory (we re-set new_mode with each EEXIST). CVSUMASK
isn't right, because typically the reason for LockDir is to
use a different set of permissions. We probably want to
inherit group ownership also (but we don't try to deal with
that, some systems do it for us either always or when g+s is on).
We don't try to do anything about the permissions on the lock
files themselves. The permissions don't really matter so much
because the locks will generally be removed by the process
which created them. */
if (CVS_STAT (lock_dir, &sb) < 0)
error (1, errno, "cannot stat %s", lock_dir);
new_mode = sb.st_mode;
save_umask = umask (0000);
saved_umask = 1;
p = short_repos;
while (1)
{
while (!ISDIRSEP (*p) && *p != '\0')
++p;
if (ISDIRSEP (*p))
{
strncpy (q, short_repos, p - short_repos);
q[p - short_repos] = '\0';
if (!ISDIRSEP (q[p - short_repos - 1])
&& CVS_MKDIR (retval, new_mode) < 0)
{
int saved_errno = errno;
if (saved_errno != EEXIST)
error (1, errno, "cannot make directory %s", retval);
else
{
if (CVS_STAT (retval, &sb) < 0)
error (1, errno, "cannot stat %s", retval);
new_mode = sb.st_mode;
}
}
++p;
}
else
{
strcpy (q, short_repos);
if (CVS_MKDIR (retval, new_mode) < 0
&& errno != EEXIST)
error (1, errno, "cannot make directory %s", retval);
goto created;
}
}
created:;
strcat (retval, "/");
strcat (retval, name);
if (saved_umask)
{
assert (umask (save_umask) == 0000);
saved_umask = 0;
}
}
return retval;
}
/*
* Clean up all outstanding locks
*/
void
Lock_Cleanup ()
{
/* FIXME: error handling here is kind of bogus; we sometimes will call
error, which in turn can call us again. For the moment work around
this by refusing to reenter this function (this is a kludge). */
/* FIXME-reentrancy: the workaround isn't reentrant. */
static int in_lock_cleanup = 0;
if (in_lock_cleanup)
return;
in_lock_cleanup = 1;
remove_locks ();
dellist (&lock_tree_list);
@ -151,6 +303,7 @@ Lock_Cleanup ()
locked_dir = NULL;
locked_list = NULL;
}
in_lock_cleanup = 0;
}
/*
@ -199,8 +352,7 @@ lock_simple_remove (lock)
existence_error here. */
if (readlock != NULL)
{
tmp = xmalloc (strlen (lock->repository) + strlen (readlock) + 10);
(void) sprintf (tmp, "%s/%s", lock->repository, readlock);
tmp = lock_name (lock->repository, readlock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
free (tmp);
@ -212,8 +364,7 @@ lock_simple_remove (lock)
existence_error here. */
if (writelock != NULL)
{
tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10);
(void) sprintf (tmp, "%s/%s", lock->repository, writelock);
tmp = lock_name (lock->repository, writelock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
free (tmp);
@ -221,8 +372,7 @@ lock_simple_remove (lock)
if (lock->have_lckdir)
{
tmp = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10);
(void) sprintf (tmp, "%s/%s", lock->repository, CVSLCK);
tmp = lock_name (lock->repository, CVSLCK);
SIG_beginCrSect ();
if (CVS_RMDIR (tmp) < 0)
error (0, errno, "failed to remove lock dir %s", tmp);
@ -283,8 +433,7 @@ Reader_Lock (xrepository)
}
/* write a read-lock */
tmp = xmalloc (strlen (xrepository) + strlen (readlock) + 10);
(void) sprintf (tmp, "%s/%s", xrepository, readlock);
tmp = lock_name (xrepository, readlock);
if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create read lock in repository `%s'",
@ -437,8 +586,7 @@ write_lock (lock)
}
/* write the write-lock file */
tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10);
(void) sprintf (tmp, "%s/%s", lock->repository, writelock);
tmp = lock_name (lock->repository, writelock);
if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
int xerrno = errno;
@ -582,8 +730,7 @@ set_lock (lock, will_wait)
if (masterlock != NULL)
free (masterlock);
masterlock = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10);
(void) sprintf (masterlock, "%s/%s", lock->repository, CVSLCK);
masterlock = lock_name (lock->repository, CVSLCK);
/*
* Note that it is up to the callers of set_lock() to arrange for signal
@ -680,13 +827,17 @@ lock_wait (repos)
char *repos;
{
time_t now;
char *msg;
(void) time (&now);
error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
lockers_name, repos);
msg = xmalloc (100 + strlen (lockers_name) + strlen (repos));
sprintf (msg, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
lockers_name, repos);
error (0, 0, "%s", msg);
/* Call cvs_flusherr to ensure that the user sees this message as
soon as possible. */
cvs_flusherr ();
free (msg);
(void) sleep (CVSLCKSLEEP);
}
@ -698,12 +849,16 @@ lock_obtained (repos)
char *repos;
{
time_t now;
char *msg;
(void) time (&now);
error (0, 0, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos);
msg = xmalloc (100 + strlen (repos));
sprintf (msg, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos);
error (0, 0, "%s", msg);
/* Call cvs_flusherr to ensure that the user sees this message as
soon as possible. */
cvs_flusherr ();
free (msg);
}
static int lock_filesdoneproc PROTO ((void *callerdat, int err,

View File

@ -5,6 +5,8 @@
* specified in the README file that comes with CVS.
*
* Allow user to log in for an authenticating server.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -48,7 +50,14 @@ construct_cvspass_filename ()
homedir = get_homedir ();
if (! homedir)
{
error (1, errno, "could not find out home directory");
/* FIXME? This message confuses a lot of users, at least
on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like
NT does). I suppose the answer for Win95 is to store the
passwords in the registry or something (??). And .cvsrc
and such too? Wonder what WinCVS does (about .cvsrc, the
right thing for a GUI is to just store the password in
memory only)... */
error (1, 0, "could not find out home directory");
return (char *) NULL;
}
@ -246,7 +255,8 @@ login (argc, argv)
/* FIXME: rename_file would make more sense (e.g. almost
always faster). */
copy_file (tmp_name, passfile);
unlink_file (tmp_name);
if (unlink_file (tmp_name) < 0)
error (0, errno, "cannot remove %s", tmp_name);
chmod (passfile, 0600);
free (tmp_name);
@ -447,6 +457,8 @@ logout (argc, argv)
*/
passfile = construct_cvspass_filename ();
/* FIXME: This should not be in /tmp; that is almost surely a security
hole. Probably should just keep it in memory. */
tmp_name = cvs_temp_name ();
if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL)
{
@ -486,14 +498,16 @@ logout (argc, argv)
if (! found)
{
printf ("Entry not found for %s\n", CVSroot_original);
unlink_file (tmp_name);
if (unlink_file (tmp_name) < 0)
error (0, errno, "cannot remove %s", tmp_name);
}
else
{
/* FIXME: rename_file would make more sense (e.g. almost
always faster). */
copy_file (tmp_name, passfile);
unlink_file (tmp_name);
if (unlink_file (tmp_name) < 0)
error (0, errno, "cannot remove %s", tmp_name);
chmod (passfile, 0600);
}
return 0;

View File

@ -4,6 +4,8 @@
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS source distribution.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -452,7 +454,8 @@ do_verify (messagep, repository)
{
/* Since following error() exits, delete the temp file
now. */
unlink_file (fname);
if (unlink_file (fname) < 0)
error (0, errno, "cannot remove %s", fname);
error (1, retcode == -1 ? errno : 0,
"Message verification failed");
@ -510,7 +513,8 @@ do_verify (messagep, repository)
/* Delete the temp file */
unlink_file (fname);
if (unlink_file (fname) < 0)
error (0, errno, "cannot remove %s", fname);
free (fname);
}
}

View File

@ -3,7 +3,10 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS kit. */
* specified in the README file that comes with the CVS kit.
*
* $FreeBSD$
*/
#include "cvs.h"
#include "savecwd.h"
@ -353,7 +356,7 @@ static const struct admin_file filelist[] = {
{CVSROOTADM_CONFIG,
"a %s file configures various behaviors",
config_contents},
{NULL, NULL}
{NULL, NULL, NULL}
};
/* Rebuild the checked out administrative files in directory DIR. */
@ -397,11 +400,6 @@ mkmodules (dir)
rename_rcsfile (temp, CVSROOTADM_MODULES);
break;
case -1: /* fork failed */
(void) unlink_file (temp);
error (1, errno, "cannot check out %s", CVSROOTADM_MODULES);
/* NOTREACHED */
default:
error (0, 0,
"'cvs checkout' is less functional without a %s file",
@ -409,7 +407,9 @@ mkmodules (dir)
break;
} /* switch on checkout_file() */
(void) unlink_file (temp);
if (unlink_file (temp) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", temp);
free (temp);
/* Checkout the files that need it in CVSROOT dir */
@ -430,7 +430,9 @@ mkmodules (dir)
else if (fileptr->errormsg)
error (0, 0, fileptr->errormsg, fileptr->filename);
#endif
(void) unlink_file (temp);
if (unlink_file (temp) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", temp);
free (temp);
}
@ -453,11 +455,13 @@ mkmodules (dir)
*last = '\0'; /* strip the newline */
/* Skip leading white space. */
for (fname = line; *fname && isspace(*fname); fname++)
for (fname = line;
*fname && isspace ((unsigned char) *fname);
fname++)
;
/* Find end of filename. */
for (cp = fname; *cp && !isspace(*cp); cp++)
for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++)
;
*cp = '\0';
@ -468,11 +472,16 @@ mkmodules (dir)
}
else
{
for (cp++; cp < last && *last && isspace(*last); cp++)
for (cp++;
cp < last && *last && isspace ((unsigned char) *last);
cp++)
;
if (cp < last && *cp)
error (0, 0, cp, fname);
}
if (unlink_file (temp) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", temp);
free (temp);
}
if (line)
@ -522,6 +531,10 @@ make_tempfile ()
return temp;
}
/* Get a file. If the file does not exist, return 1 silently. If
there is an error, print a message and return 1 (FIXME: probably
not a very clean convention). On success, return 0. */
static int
checkout_file (file, temp)
char *file;
@ -547,6 +560,8 @@ checkout_file (file, temp)
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
{
/* Probably not necessary (?); RCS_checkout already printed a
message. */
error (0, 0, "failed to check out %s file",
file);
}
@ -607,7 +622,7 @@ write_dbmfile (temp)
if (value[0] == '#')
continue; /* comment line */
vp = value;
while (*vp && isspace (*vp))
while (*vp && isspace ((unsigned char) *vp))
vp++;
if (*vp == '\0')
continue; /* empty line */
@ -618,11 +633,11 @@ write_dbmfile (temp)
if (!cont)
{
key.dptr = vp;
while (*vp && !isspace (*vp))
while (*vp && !isspace ((unsigned char) *vp))
vp++;
key.dsize = vp - key.dptr;
*vp++ = '\0'; /* NULL terminate the key */
while (*vp && isspace (*vp))
while (*vp && isspace ((unsigned char) *vp))
vp++; /* skip whitespace to value */
if (*vp == '\0')
{
@ -639,17 +654,28 @@ write_dbmfile (temp)
}
}
dbm_close (db);
(void) fclose (fp);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", temp);
if (err)
{
/* I think that the size of the buffer needed here is
just determined by sizeof (CVSROOTADM_MODULES), the
filenames created by make_tempfile, and other things that won't
overflow. */
char dotdir[50], dotpag[50], dotdb[50];
(void) sprintf (dotdir, "%s.dir", temp);
(void) sprintf (dotpag, "%s.pag", temp);
(void) sprintf (dotdb, "%s.db", temp);
(void) unlink_file (dotdir);
(void) unlink_file (dotpag);
(void) unlink_file (dotdb);
if (unlink_file (dotdir) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", dotdir);
if (unlink_file (dotpag) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", dotpag);
if (unlink_file (dotdb) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", dotdb);
error (1, 0, "DBM creation failed; correct above errors");
}
}
@ -658,10 +684,18 @@ static void
rename_dbmfile (temp)
char *temp;
{
/* I think that the size of the buffer needed here is
just determined by sizeof (CVSROOTADM_MODULES), the
filenames created by make_tempfile, and other things that won't
overflow. */
char newdir[50], newpag[50], newdb[50];
char dotdir[50], dotpag[50], dotdb[50];
char bakdir[50], bakpag[50], bakdb[50];
int dir1_errno = 0, pag1_errno = 0, db1_errno = 0;
int dir2_errno = 0, pag2_errno = 0, db2_errno = 0;
int dir3_errno = 0, pag3_errno = 0, db3_errno = 0;
(void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
(void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
(void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES);
@ -679,18 +713,59 @@ rename_dbmfile (temp)
/* don't mess with me */
SIG_beginCrSect ();
(void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
(void) unlink_file (bakpag);
(void) unlink_file (bakdb);
(void) CVS_RENAME (dotdir, bakdir); /* mv modules.dir .#modules.dir */
(void) CVS_RENAME (dotpag, bakpag); /* mv modules.pag .#modules.pag */
(void) CVS_RENAME (dotdb, bakdb); /* mv modules.db .#modules.db */
(void) CVS_RENAME (newdir, dotdir); /* mv "temp".dir modules.dir */
(void) CVS_RENAME (newpag, dotpag); /* mv "temp".pag modules.pag */
(void) CVS_RENAME (newdb, dotdb); /* mv "temp".db modules.db */
/* rm .#modules.dir .#modules.pag */
if (unlink_file (bakdir) < 0)
dir1_errno = errno;
if (unlink_file (bakpag) < 0)
pag1_errno = errno;
if (unlink_file (bakdb) < 0)
db1_errno = errno;
/* mv modules.dir .#modules.dir */
if (CVS_RENAME (dotdir, bakdir) < 0)
dir2_errno = errno;
/* mv modules.pag .#modules.pag */
if (CVS_RENAME (dotpag, bakpag) < 0)
pag2_errno = errno;
/* mv modules.db .#modules.db */
if (CVS_RENAME (dotdb, bakdb) < 0)
db2_errno = errno;
/* mv "temp".dir modules.dir */
if (CVS_RENAME (newdir, dotdir) < 0)
dir3_errno = errno;
/* mv "temp".pag modules.pag */
if (CVS_RENAME (newpag, dotpag) < 0)
pag3_errno = errno;
/* mv "temp".db modules.db */
if (CVS_RENAME (newdb, dotdb) < 0)
db3_errno = errno;
/* OK -- make my day */
SIG_endCrSect ();
/* I didn't want to call error() when we had signals blocked
(unnecessary?), but do it now. */
if (dir1_errno && !existence_error (dir1_errno))
error (0, dir1_errno, "cannot remove %s", bakdir);
if (pag1_errno && !existence_error (pag1_errno))
error (0, pag1_errno, "cannot remove %s", bakpag);
if (db1_errno && !existence_error (db1_errno))
error (0, db1_errno, "cannot remove %s", bakdb);
if (dir2_errno && !existence_error (dir2_errno))
error (0, dir2_errno, "cannot remove %s", bakdir);
if (pag2_errno && !existence_error (pag2_errno))
error (0, pag2_errno, "cannot remove %s", bakpag);
if (db2_errno && !existence_error (db2_errno))
error (0, db2_errno, "cannot remove %s", bakdb);
if (dir3_errno && !existence_error (dir3_errno))
error (0, dir3_errno, "cannot remove %s", bakdir);
if (pag3_errno && !existence_error (pag3_errno))
error (0, pag3_errno, "cannot remove %s", bakpag);
if (db3_errno && !existence_error (db3_errno))
error (0, db3_errno, "cannot remove %s", bakdb);
}
#endif /* !MY_NDBM */
@ -708,16 +783,31 @@ rename_rcsfile (temp, real)
rcs = xmalloc (strlen (real) + sizeof (RCSEXT) + 10);
(void) sprintf (rcs, "%s%s", real, RCSEXT);
statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
(void) CVS_STAT (rcs, &statbuf);
if (CVS_STAT (rcs, &statbuf) < 0
&& !existence_error (errno))
error (0, errno, "cannot stat %s", rcs);
free (rcs);
if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
error (0, errno, "warning: cannot chmod %s", temp);
bak = xmalloc (strlen (real) + sizeof (BAKPREFIX) + 10);
(void) sprintf (bak, "%s%s", BAKPREFIX, real);
(void) unlink_file (bak); /* rm .#loginfo */
(void) CVS_RENAME (real, bak); /* mv loginfo .#loginfo */
(void) CVS_RENAME (temp, real); /* mv "temp" loginfo */
/* rm .#loginfo */
if (unlink_file (bak) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", bak);
/* mv loginfo .#loginfo */
if (CVS_RENAME (real, bak) < 0
&& !existence_error (errno))
error (0, errno, "cannot rename %s to %s", real, bak);
/* mv "temp" loginfo */
if (CVS_RENAME (temp, real) < 0
&& !existence_error (errno))
error (0, errno, "cannot rename %s to %s", temp, real);
free (bak);
}

View File

@ -6,6 +6,8 @@
*
* The routines contained in this file do all the rcs file parsing and
* manipulation
*
* $FreeBSD$
*/
#include <assert.h>
@ -155,6 +157,26 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
static char *rcs_lockfile;
/* A few generic thoughts on error handling, in particular the
printing of unexpected characters that we find in the RCS file
(that is, why we use '\x%x' rather than %c or some such).
* Avoiding %c means we don't have to worry about what is printable
and other such stuff. In error handling, often better to keep it
simple.
* Hex rather than decimal or octal because character set standards
tend to use hex.
* Saying "character 0x%x" might make it sound like we are printing
a file offset. So we use '\x%x'.
* Would be nice to print the offset within the file, but I can
imagine various portability hassles (in particular, whether
unsigned long is always big enough to hold file offsets). */
/* Parse an rcsfile given a user file name and a repository. If there is
an error, we print an error message and return NULL. If the file
does not exist, we return NULL without printing anything (I'm not
@ -366,7 +388,9 @@ RCS_parsercsfile_i (fp, rcsfile)
break;
}
for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
for (cp = key;
(isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
cp++)
/* do nothing */ ;
if (*cp == '\0')
break;
@ -500,7 +524,9 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
* revision or `desc', we are done with the headers and are down to the
* revision deltas, so we break out of the loop
*/
for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
for (cp = key;
(isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK
@ -585,6 +611,98 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
rdata->flags &= ~PARTIAL;
}
/* Move RCS into or out of the Attic, depending on TOATTIC. If the
file is already in the desired place, return without doing
anything. At some point may want to think about how this relates
to RCS_rewrite but that is a bit hairy (if one wants renames to be
atomic, or that kind of thing). If there is an error, print a message
and return 1. On success, return 0. */
int
RCS_setattic (rcs, toattic)
RCSNode *rcs;
int toattic;
{
char *newpath;
char *p;
char *q;
/* Some systems aren't going to let us rename an open file. */
rcsbuf_cache_close ();
/* Could make the pathname computations in this file, and probably
in other parts of rcs.c too, easier if the REPOS and FILE
arguments to RCS_parse got stashed in the RCSNode. */
if (toattic)
{
mode_t omask;
if (rcs->flags & INATTIC)
return 0;
/* Example: rcs->path is "/foo/bar/baz,v". */
newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
p = last_component (rcs->path);
strncpy (newpath, rcs->path, p - rcs->path);
strcpy (newpath + (p - rcs->path), CVSATTIC);
/* Create the Attic directory if it doesn't exist. */
omask = umask (cvsumask);
if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
error (0, errno, "cannot make directory %s", newpath);
(void) umask (omask);
strcat (newpath, "/");
strcat (newpath, p);
if (CVS_RENAME (rcs->path, newpath) < 0)
{
int save_errno = errno;
/* The checks for isreadable look awfully fishy, but
I'm going to leave them here for now until I
can think harder about whether they take care of
some cases which should be handled somehow. */
if (isreadable (rcs->path) || !isreadable (newpath))
{
error (0, save_errno, "cannot rename %s to %s",
rcs->path, newpath);
free (newpath);
return 1;
}
}
}
else
{
if (!(rcs->flags & INATTIC))
return 0;
newpath = xmalloc (strlen (rcs->path));
/* Example: rcs->path is "/foo/bar/Attic/baz,v". */
p = last_component (rcs->path);
strncpy (newpath, rcs->path, p - rcs->path - 1);
newpath[p - rcs->path - 1] = '\0';
q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
strcpy (q, p);
if (CVS_RENAME (rcs->path, newpath) < 0)
{
error (0, errno, "failed to move `%s' out of the attic",
rcs->path);
free (newpath);
return 1;
}
}
free (rcs->path);
rcs->path = newpath;
return 0;
}
/*
* Fully parse the RCS file. Store all keyword/value pairs, fetch the
* log messages for each revision, and fetch add and delete counts for
@ -673,7 +791,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
op = *cp++;
if (op != 'a' && op != 'd')
error (1, 0, "unrecognized operation '%c' in %s",
error (1, 0, "\
unrecognized operation '\\x%x' in %s",
op, rcs->path);
(void) strtoul (cp, (char **) &cp, 10);
if (*cp++ != ' ')
@ -1481,7 +1600,8 @@ rcsbuf_getstring (rcsbuf, strp)
/* PTR should now point to the start of a string. */
if (c != '@')
error (1, 0, "expected @-string at `%c' in %s", c, rcsbuf->filename);
error (1, 0, "expected @-string at '\\x%x' in %s",
c, rcsbuf->filename);
/* Optimize the common case of a value composed of a single
'@' string. */
@ -1738,7 +1858,7 @@ rcsbuf_getword (rcsbuf, wordp)
printing character that is not a special.' This test ought
to do the trick. */
c = *ptr;
if (isprint (c) &&
if (isprint ((unsigned char) c) &&
c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
{
++ptr;
@ -1806,9 +1926,10 @@ rcsbuf_getrevnum (rcsbuf, revp)
++ptr;
}
if (! isdigit (c) && c != '.')
if (! isdigit ((unsigned char) c) && c != '.')
error (1, 0,
"unexpected `%c' reading revision number in RCS file %s",
"\
unexpected '\\x%x' reading revision number in RCS file %s",
c, rcsbuf->filename);
*revp = ptr;
@ -1828,10 +1949,11 @@ rcsbuf_getrevnum (rcsbuf, revp)
c = *ptr;
}
while (isdigit (c) || c == '.');
while (isdigit ((unsigned char) c) || c == '.');
if (! whitespace (c))
error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
error (1, 0, "\
unexpected '\\x%x' reading revision number in RCS file %s",
c, rcsbuf->filename);
*ptr = '\0';
@ -2339,7 +2461,7 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
}
/* Work out the branch. */
if (! isdigit (tag[0]))
if (! isdigit ((unsigned char) tag[0]))
branch = RCS_whatbranch (rcs, tag);
else
branch = xstrdup (tag);
@ -2404,6 +2526,16 @@ RCS_tag2rev (rcs, tag)
}
}
/* Try for a real (that is, exists in the RCS deltas) branch
(RCS_exist_rev just checks for real revisions and revisions
which have tags pointing to them). */
pa = RCS_getbranch (rcs, rev, 1);
if (pa != NULL)
{
free (pa);
return rev;
}
/* Tag is branch, but does not exist, try corresponding
* magic branch tag.
*
@ -2427,7 +2559,7 @@ RCS_tag2rev (rcs, tag)
RCS_check_tag (tag); /* exit if not a valid tag */
/* If tag is "HEAD", special case to get head RCS revision */
if (tag && (strcmp (tag, TAG_HEAD) == 0))
if (tag && STREQ (tag, TAG_HEAD))
return (RCS_head (rcs));
/* If valid tag let translate_symtag say yea or nay. */
@ -2480,7 +2612,7 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
#endif
return (RCS_head (rcs));
if (!isdigit (tag[0]))
if (!isdigit ((unsigned char) tag[0]))
{
char *version;
@ -2689,7 +2821,7 @@ RCS_isbranch (rcs, rev)
const char *rev;
{
/* numeric revisions are easy -- even number of dots is a branch */
if (isdigit (*rev))
if (isdigit ((unsigned char) *rev))
return ((numdots (rev) & 1) == 0);
/* assume a revision if you can't find the RCS info */
@ -2716,7 +2848,7 @@ RCS_nodeisbranch (rcs, rev)
assert (rcs != NULL);
/* numeric revisions are easy -- even number of dots is a branch */
if (isdigit (*rev))
if (isdigit ((unsigned char) *rev))
return ((numdots (rev) & 1) == 0);
version = translate_symtag (rcs, rev);
@ -2943,7 +3075,7 @@ RCS_branch_head (rcs, rev)
if (RCS_nodeisbranch (rcs, rev))
return RCS_getbranch (rcs, rev, 1);
if (isdigit (*rev))
if (isdigit ((unsigned char) *rev))
num = xstrdup (rev);
else
{
@ -3115,8 +3247,23 @@ RCS_getdate (rcs, date, force_tag_match)
*/
/* if we found what we're looking for, and it's not 1.1 return it */
if (cur_rev != NULL && ! STREQ (cur_rev, "1.1"))
return (xstrdup (cur_rev));
if (cur_rev != NULL)
{
if (! STREQ (cur_rev, "1.1"))
return (xstrdup (cur_rev));
/* This is 1.1; if the date of 1.1 is not the same as that for the
1.1.1.1 version, then return 1.1. This happens when the first
version of a file is created by a regular cvs add and commit,
and there is a subsequent cvs import of the same file. */
p = findnode (rcs->versions, "1.1.1.1");
if (p)
{
vers = (RCSVers *) p->data;
if (RCS_datecmp (vers->date, date) != 0)
return xstrdup ("1.1");
}
}
/* look on the vendor branch */
retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
@ -3468,11 +3615,11 @@ RCS_check_tag (tag)
* characters cannot be non-visible graphic characters, and must not be
* in the set of "invalid" RCS identifier characters.
*/
if (isalpha (*tag))
if (isalpha ((unsigned char) *tag))
{
for (cp = tag; *cp; cp++)
{
if (!isgraph (*cp))
if (!isgraph ((unsigned char) *cp))
error (1, 0, "tag `%s' has non-visible graphic characters",
tag);
if (strchr (invalid, *cp))
@ -3499,7 +3646,7 @@ RCS_valid_rev (rev)
{
char last, c;
last = *rev++;
if (!isdigit (last))
if (!isdigit ((unsigned char) last))
return 0;
while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
{
@ -3510,10 +3657,10 @@ RCS_valid_rev (rev)
continue;
}
last = c;
if (!isdigit (c))
if (!isdigit ((unsigned char) c))
return 0;
}
if (!isdigit (last))
if (!isdigit ((unsigned char) last))
return 0;
return 1;
}
@ -3549,10 +3696,26 @@ char *
RCS_getexpand (rcs)
RCSNode *rcs;
{
/* Since RCS_parsercsfile_i now reads expand, don't need to worry
about RCS_reparsercsfile. */
assert (rcs != NULL);
return rcs->expand;
}
/* Set keyword expansion mode to EXPAND. For example "b" for binary. */
void
RCS_setexpand (rcs, expand)
RCSNode *rcs;
char *expand;
{
/* Since RCS_parsercsfile_i now reads expand, don't need to worry
about RCS_reparsercsfile. */
assert (rcs != NULL);
if (rcs->expand != NULL)
free (rcs->expand);
rcs->expand = xstrdup (expand);
}
/* RCS keywords, and a matching enum. */
struct rcs_keyword
{
@ -3760,7 +3923,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
/* Look for the first non alphabetic character after the '$'. */
send = srch + srch_len;
for (s = srch; s < send; s++)
if (! isalpha (*s))
if (! isalpha ((unsigned char) *s))
break;
/* If the first non alphabetic character is not '$' or ':',
@ -3876,7 +4039,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
break;
case KEYWORD_NAME:
if (name != NULL && ! isdigit (*name))
if (name != NULL && ! isdigit ((unsigned char) *name))
value = (char *) name;
else
value = NULL;
@ -4219,7 +4382,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
: (sout != RUN_TTY ? sout : "(stdout)"))));
}
assert (rev == NULL || isdigit (*rev));
assert (rev == NULL || isdigit ((unsigned char) *rev));
if (noexec && workfile != NULL)
return 0;
@ -4467,9 +4630,9 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
error (1, 0, "%s:%s has bad `special' newphrase %s",
workfile, vers->version, info->data);
devnum = devnum_long;
if (strcmp (devtype, "character") == 0)
if (STREQ (devtype, "character"))
special_file = S_IFCHR;
else if (strcmp (devtype, "block") == 0)
else if (STREQ (devtype, "block"))
special_file = S_IFBLK;
else
error (0, 0, "%s is a special file of unsupported type `%s'",
@ -5030,6 +5193,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
struct tm *ftm;
time_t modtime;
int adding_branch = 0;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
struct stat sb;
#endif
commitpt = NULL;
@ -5050,40 +5216,11 @@ RCS_checkin (rcs, workfile, message, rev, flags)
allocated_workfile = 1;
}
/* Is the backend file a symbolic link? Follow it and replace the
filename with the destination of the link. */
while (islink (rcs->path))
{
char *newname;
#ifdef HAVE_READLINK
/* The clean thing to do is probably to have each filesubr.c
implement this (with an error if not supported by the
platform, in which case islink would presumably return 0).
But that would require editing each filesubr.c and so the
expedient hack seems to be looking at HAVE_READLINK. */
newname = xreadlink (rcs->path);
#else
error (1, 0, "internal error: islink doesn't like readlink");
#endif
if (isabsolute (newname))
{
free (rcs->path);
rcs->path = newname;
}
else
{
char *oldname = last_component (rcs->path);
int dirlen = oldname - rcs->path;
char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
strncpy (fullnewname, rcs->path, dirlen);
strcpy (fullnewname + dirlen, newname);
free (newname);
free (rcs->path);
rcs->path = fullnewname;
}
}
/* If the filename is a symbolic link, follow it and replace it
with the destination of the link. We need to do this before
calling rcs_internal_lockfile, or else we won't put the lock in
the right place. */
resolve_symlink (&(rcs->path));
checkin_quiet = flags & RCS_FLAGS_QUIET;
if (!checkin_quiet)
@ -5129,7 +5266,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (preserve_perms)
{
Node *np;
struct stat sb;
char buf[64]; /* static buffer should be safe: see usage. -twp */
delta->other_delta = getlist();
@ -5228,6 +5364,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
dtext->version = xstrdup (newrev);
bufsize = 0;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
if (preserve_perms && !S_ISREG (sb.st_mode))
/* Pretend file is empty. */
bufsize = 0;
else
#endif
get_file (workfile, workfile,
rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
&dtext->text, &bufsize, &dtext->len);
@ -5310,7 +5452,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
char *branch, *tip, *newrev, *p;
int dots, isrevnum;
assert (isdigit(*rev));
assert (isdigit ((unsigned char) *rev));
newrev = xstrdup (rev);
dots = numdots (newrev);
@ -5465,6 +5607,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
/* If this revision is being inserted on the trunk, the change text
for the new delta should be the contents of the working file ... */
bufsize = 0;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
if (preserve_perms && !S_ISREG (sb.st_mode))
/* Pretend file is empty. */
;
else
#endif
get_file (workfile, workfile,
rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
&dtext->text, &bufsize, &dtext->len);
@ -6539,8 +6687,23 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
char *diffbuf;
size_t bufsize, len;
#if defined (__CYGWIN32__) || defined (_WIN32)
/* FIXME: This is an awful kludge, but at least until I have
time to work on it a little more and test it, I'd rather
give a fatal error than corrupt the file. I think that we
need to use "-kb" and "--binary" and "rb" to get_file
(probably can do it always, not just for binary files, if
we are consistent between the RCS_checkout and the diff). */
{
char *expand = RCS_getexpand (rcs);
if (expand != NULL && STREQ (expand, "b"))
error (1, 0,
"admin -o not implemented yet for binary on this system");
}
#endif
afterfile = cvs_temp_name();
status = RCS_checkout (rcs, NULL, after, NULL, NULL, afterfile,
status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
(RCSCHECKOUTPROC)0, NULL);
if (status > 0)
goto delrev_done;
@ -6568,13 +6731,13 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
else
{
beforefile = cvs_temp_name();
status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
(RCSCHECKOUTPROC)0, NULL);
if (status > 0)
goto delrev_done;
outfile = cvs_temp_name();
status = diff_exec (beforefile, afterfile, "-n", outfile);
status = diff_exec (beforefile, afterfile, "-an", outfile);
if (status == 2)
{
@ -7024,7 +7187,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
we define a deltafrag as an add or a delete) need to be applied
in reverse order. So we stick them into a linked list. */
struct deltafrag {
enum {ADD, DELETE} type;
enum {FRAG_ADD, FRAG_DELETE} type;
unsigned long pos;
unsigned long nlines;
const char *new_lines;
@ -7041,7 +7204,8 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
if (op != 'a' && op != 'd')
/* Can't just skip over the deltafrag, because the value
of op determines the syntax. */
error (1, 0, "unrecognized operation '%c' in %s", op, name);
error (1, 0, "unrecognized operation '\\x%x' in %s",
op, name);
df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
df->next = dfhead;
dfhead = df;
@ -7063,7 +7227,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
{
unsigned int i;
df->type = ADD;
df->type = FRAG_ADD;
i = df->nlines;
/* The text we want is the number of lines specified, or
until the end of the value, whichever comes first (it
@ -7093,7 +7257,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
--df->pos;
assert (op == 'd');
df->type = DELETE;
df->type = FRAG_DELETE;
}
}
@ -7103,12 +7267,12 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
switch (df->type)
{
case ADD:
case FRAG_ADD:
if (! linevector_add (lines, df->new_lines, df->len, addvers,
df->pos))
return 0;
break;
case DELETE:
case FRAG_DELETE:
if (df->pos > lines->nlines
|| df->pos + df->nlines > lines->nlines)
return 0;
@ -7567,7 +7731,9 @@ getdelta (rcsbuf, rcsfile, keyp, valp)
/* Make sure that it is a revision number and not a cabbage
or something. */
for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
for (cp = key;
(isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK since
@ -7751,7 +7917,9 @@ unable to parse %s; `state' not in the expected place", rcsfile);
continue;
}
/* if we have a new revision number, we're done with this delta */
for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
for (cp = key;
(isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK
@ -8333,6 +8501,30 @@ count_delta_actions (np, ignore)
return 0;
}
/*
* Clean up temporary files
*/
static RETSIGTYPE
rcs_cleanup ()
{
/* Note that the checks for existence_error are because we are
called from a signal handler, so we don't know whether the
files got created. */
/* FIXME: Do not perform buffered I/O from an interrupt handler like
this (via error). However, I'm leaving the error-calling code there
in the hope that on the rare occasion the error call is actually made
(e.g., a fluky I/O error or permissions problem prevents the deletion
of a just-created file) reentrancy won't be an issue. */
if (rcs_lockfile != NULL)
{
if (unlink_file (rcs_lockfile) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", rcs_lockfile);
}
rcs_lockfile = NULL;
}
/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
locking on the specified RCSFILE: for a file called `foo,v', open
for writing a file called `,foo,'.
@ -8357,10 +8549,6 @@ count_delta_actions (np, ignore)
processes from stomping all over each other's laundry. Hence,
they are `internal' locking functions.
Note that we don't clean up the ,foo, file on ^C. We probably should.
I'm not completely sure whether RCS does or not (I looked at the code
a little, and didn't find it).
If there is an error, give a fatal error; if we return we always
return a non-NULL value. */
@ -8368,13 +8556,35 @@ static FILE *
rcs_internal_lockfile (rcsfile)
char *rcsfile;
{
char *lockfile;
int fd;
struct stat rstat;
FILE *fp;
static int first_call = 1;
if (first_call)
{
first_call = 0;
/* clean up if we get a signal */
#ifdef SIGHUP
(void) SIG_register (SIGHUP, rcs_cleanup);
#endif
#ifdef SIGINT
(void) SIG_register (SIGINT, rcs_cleanup);
#endif
#ifdef SIGQUIT
(void) SIG_register (SIGQUIT, rcs_cleanup);
#endif
#ifdef SIGPIPE
(void) SIG_register (SIGPIPE, rcs_cleanup);
#endif
#ifdef SIGTERM
(void) SIG_register (SIGTERM, rcs_cleanup);
#endif
}
/* Get the lock file name: `,file,' for RCS file `file,v'. */
lockfile = rcs_lockfilename (rcsfile);
assert (rcs_lockfile == NULL);
rcs_lockfile = rcs_lockfilename (rcsfile);
/* Use the existing RCS file mode, or read-only if this is a new
file. (Really, this is a lie -- if this is a new file,
@ -8400,12 +8610,13 @@ rcs_internal_lockfile (rcsfile)
rely on O_EXCL these days. This might be true for unix (I
don't really know), but I am still pretty skeptical in the case
of the non-unix systems. */
fd = open (lockfile, OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
fd = open (rcs_lockfile,
OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
S_IRUSR | S_IRGRP | S_IROTH);
if (fd < 0)
{
error (1, errno, "could not open lock file `%s'", lockfile);
error (1, errno, "could not open lock file `%s'", rcs_lockfile);
}
/* Force the file permissions, and return a stream object. */
@ -8413,11 +8624,11 @@ rcs_internal_lockfile (rcsfile)
this in the non-HAVE_FCHMOD case. */
#ifdef HAVE_FCHMOD
if (fchmod (fd, rstat.st_mode) < 0)
error (1, errno, "cannot change mode for %s", lockfile);
error (1, errno, "cannot change mode for %s", rcs_lockfile);
#endif
fp = fdopen (fd, FOPEN_BINARY_WRITE);
if (fp == NULL)
error (1, errno, "cannot fdopen %s", lockfile);
error (1, errno, "cannot fdopen %s", rcs_lockfile);
free (lockfile);
@ -8429,10 +8640,7 @@ rcs_internal_unlockfile (fp, rcsfile)
FILE *fp;
char *rcsfile;
{
char *lockfile;
/* Get the lock file name: `,file,' for RCS file `file,v'. */
lockfile = rcs_lockfilename (rcsfile);
assert (rcs_lockfile != NULL);
/* Abort if we could not write everything successfully to LOCKFILE.
This is not a great error-handling mechanism, but should prevent
@ -8445,12 +8653,21 @@ rcs_internal_unlockfile (fp, rcsfile)
fragile even if it happens to sometimes be true. The real
solution is to check each call to fprintf rather than waiting
until the end like this. */
error (1, 0, "error writing to lock file %s", lockfile);
error (1, 0, "error writing to lock file %s", rcs_lockfile);
if (fclose (fp) == EOF)
error (1, errno, "error closing lock file %s", lockfile);
error (1, errno, "error closing lock file %s", rcs_lockfile);
rename_file (lockfile, rcsfile);
free (lockfile);
rename_file (rcs_lockfile, rcsfile);
{
/* Use a temporary to make sure there's no interval
(after rcs_lockfile has been freed but before it's set to NULL)
during which the signal handler's use of rcs_lockfile would
reference freed memory. */
char *tmp = rcs_lockfile;
rcs_lockfile = NULL;
free (tmp);
}
}
static char *
@ -8493,6 +8710,9 @@ RCS_rewrite (rcs, newdtext, insertpt)
if (noexec)
return;
/* Make sure we're operating on an actual file and not a symlink. */
resolve_symlink (&(rcs->path));
fout = rcs_internal_lockfile (rcs->path);
RCS_putadmin (rcs, fout);
@ -8571,8 +8791,8 @@ annotate_fileproc (callerdat, finfo)
cvs_outerr (finfo->fullname, 0);
cvs_outerr ("\n***************\n", 0);
RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, (char **) NULL,
(size_t) NULL, (char **) NULL, (size_t *) NULL);
RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL,
NULL, NULL, NULL);
free (version);
return 0;
}
@ -8645,8 +8865,8 @@ annotate (argc, argv)
option_with_arg ("-r", tag);
if (date)
client_senddate (date);
send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("annotate\012", 0);
return get_responses_and_close ();
}
@ -8682,7 +8902,7 @@ make_file_label (path, rev, rcs)
char *file;
file = last_component (path);
label = (char *) xmalloc (strlen (file)
label = (char *) xmalloc (strlen (path)
+ (rev == NULL ? 0 : strlen (rev))
+ 50);
@ -8691,7 +8911,7 @@ make_file_label (path, rev, rcs)
char *date;
RCS_getrevtime (rcs, rev, datebuf, 0);
date = printable_date (datebuf);
(void) sprintf (label, "-L%s\t%s\t%s", file, date, rev);
(void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
free (date);
}
else
@ -8708,7 +8928,7 @@ make_file_label (path, rev, rcs)
wm->tm_year + 1900, wm->tm_mon + 1,
wm->tm_mday, wm->tm_hour,
wm->tm_min, wm->tm_sec);
(void) sprintf (label, "-L%s\t%s", file, datebuf);
(void) sprintf (label, "-L%s\t%s", path, datebuf);
}
}
return label;

View File

@ -6,6 +6,8 @@
* specified in the README file that comes with the CVS source distribution.
*
* RCS source control definitions needed by rcs.c and friends
*
* $FreeBSD$
*/
/* String which indicates a conflict if it occurs at the start of a line. */
@ -184,6 +186,7 @@ RCSNode *RCS_parse PROTO((const char *file, const char *repos));
RCSNode *RCS_parsercsfile PROTO((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));
@ -211,6 +214,7 @@ 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,

View File

@ -7,6 +7,8 @@
*
* The functions in this file provide an interface for performing
* operations directly on RCS files.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -147,7 +149,8 @@ call_diff_write_output (text, len)
const char *text;
size_t len;
{
cvs_output (text, len);
if (len > 0)
cvs_output (text, len);
}
/* Call back function for the diff library to flush the output file.

View File

@ -6,6 +6,7 @@
*
* General recursion handler
*
* $FreeBSD$
*/
#include "cvs.h"
@ -13,9 +14,6 @@
#include "fileattr.h"
#include "edit.h"
#ifdef CLIENT_SUPPORT
static int do_argument_proc PROTO((Node * p, void *closure));
#endif
static int do_dir_proc PROTO((Node * p, void *closure));
static int do_file_proc PROTO((Node * p, void *closure));
static void addlist PROTO((List ** listp, char *key));
@ -61,23 +59,6 @@ struct frame_and_entries {
List *entries;
};
#ifdef CLIENT_SUPPORT
/* This is a callback to send "Argument" commands to the server in the
case we've done a "cvs update" or "cvs commit" in a top-level
directory where there is no CVSADM directory. */
static int
do_argument_proc (p, closure)
Node *p;
void *closure;
{
char *dir = p->key;
send_to_server ("Argument ", 0);
send_to_server (dir, 0);
send_to_server ("\012", 1);
return 0;
}
#endif
/* Start a recursive command.
@ -127,6 +108,9 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
int dosrcs;
{
int i, err = 0;
#ifdef CLIENT_SUPPORT
List *args_to_send_when_finished = NULL;
#endif
List *files_by_dir = NULL;
struct recursion_frame frame;
@ -169,6 +153,29 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
if (argc == 0)
{
int just_subdirs = (which & W_LOCAL) && !isdir (CVSADM);
#ifdef CLIENT_SUPPORT
if (!just_subdirs
&& CVSroot_cmdline == NULL
&& client_active)
{
char *root = Name_Root (NULL, update_dir);
if (root && strcmp (root, current_root) != 0)
/* We're skipping this directory because it is for
a different root. Therefore, we just want to
do the subdirectories only. Processing files would
cause a working directory from one repository to be
processed against a different repository, which could
cause all kinds of spurious conflicts and such.
Question: what about the case of "cvs update foo"
where we process foo/bar and not foo itself? That
seems to be handled somewhere (else) but why should
it be a separate case? Needs investigation... */
just_subdirs = 1;
}
#endif
/*
* There were no arguments, so we'll probably just recurse. The
@ -177,7 +184,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
* process each of the sub-directories, so we pretend like we were
* called with the list of sub-dirs of the current dir as args
*/
if ((which & W_LOCAL) && !isdir (CVSADM))
if (just_subdirs)
{
dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL);
/* If there are no sub-directories, there is a certain logic in
@ -204,17 +211,21 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
appropriate "Argument" commands to the server. In
this case, that won't have happened, so we need to
do it here. While this example uses "update", this
generalizes to other commands. */
generalizes to other commands. */
err += walklist (dirlist, do_argument_proc, NULL);
/* This is the same call to Find_Directories as above.
FIXME: perhaps it would be better to write a
function that duplicates a list. */
args_to_send_when_finished = Find_Directories ((char *) NULL,
W_LOCAL,
(List *) NULL);
}
#endif
}
else
addlist (&dirlist, ".");
err += do_recursion (&frame);
goto out;
goto do_the_work;
}
@ -335,14 +346,146 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
/* then do_recursion on the dirlist. */
if (dirlist != NULL)
{
do_the_work:
err += do_recursion (&frame);
}
/* Free the data which expand_wild allocated. */
free_names (&argc, argv);
out:
free (update_dir);
update_dir = NULL;
#ifdef CLIENT_SUPPORT
if (args_to_send_when_finished != NULL)
{
/* FIXME (njc): in the multiroot case, we don't want to send
argument commands for those top-level directories which do
not contain any subdirectories which have files checked out
from current_root. If we do, and two repositories have a
module with the same name, nasty things could happen.
This is hard. Perhaps we should send the Argument commands
later in this procedure, after we've had a chance to notice
which directores we're using (after do_recursion has been
called once). This means a _lot_ of rewriting, however.
What we need to do for that to happen is descend the tree
and construct a list of directories which are checked out
from current_cvsroot. Now, we eliminate from the list all
of those directories which are immediate subdirectories of
another directory in the list. To say that the opposite
way, we keep the directories which are not immediate
subdirectories of any other in the list. Here's a picture:
a
/ \
B C
/ \
D e
/ \
F G
/ \
H I
The node in capitals are those directories which are
checked out from current_cvsroot. We want the list to
contain B, C, F, and G. D, H, and I are not included,
because their parents are also checked out from
current_cvsroot.
The algorithm should be:
1) construct a tree of all directory names where each
element contains a directory name and a flag which notes if
that directory is checked out from current_cvsroot
a0
/ \
B1 C1
/ \
D1 e0
/ \
F1 G1
/ \
H1 I1
2) Recursively descend the tree. For each node, recurse
before processing the node. If the flag is zero, do
nothing. If the flag is 1, check the node's parent. If
the parent's flag is one, change the current entry's flag
to zero.
a0
/ \
B1 C1
/ \
D0 e0
/ \
F1 G1
/ \
H0 I0
3) Walk the tree and spit out "Argument" commands to tell
the server which directories to munge.
Yuck. It's not clear this is worth spending time on, since
we might want to disable cvs commands entirely from
directories that do not have CVSADM files...
Anyways, the solution as it stands has modified server.c
(dirswitch) to create admin files [via server.c
(create_adm_p)] in all path elements for a client's
"Directory xxx" command, which forces the server to descend
and serve the files there. client.c (send_file_names) has
also been modified to send only those arguments which are
appropriate to current_root.
*/
/* Construct a fake argc/argv pair. */
int our_argc = 0, i;
char **our_argv = NULL;
if (! list_isempty (args_to_send_when_finished))
{
Node *head, *p;
head = args_to_send_when_finished->list;
/* count the number of nodes */
i = 0;
for (p = head->next; p != head; p = p->next)
i++;
our_argc = i;
/* create the argument vector */
our_argv = (char **) xmalloc (sizeof (char *) * our_argc);
/* populate it */
i = 0;
for (p = head->next; p != head; p = p->next)
our_argv[i++] = xstrdup (p->key);
}
/* We don't want to expand widcards, since we've just created
a list of directories directly from the filesystem. */
send_file_names (our_argc, our_argv, 0);
/* Free our argc/argv. */
if (our_argv != NULL)
{
for (i = 0; i < our_argc; i++)
free (our_argv[i]);
free (our_argv);
}
dellist (&args_to_send_when_finished);
}
#endif
return (err);
}
@ -359,6 +502,7 @@ do_recursion (frame)
char *srepository;
List *entries = NULL;
int should_readlock;
int process_this_directory = 1;
/* do nothing if told */
if (frame->flags == R_SKIP_ALL)
@ -410,6 +554,57 @@ do_recursion (frame)
server_pause_check();
#endif
/* Check the value in CVSADM_ROOT and see if it's in the list. If
not, add it to our lists of CVS/Root directories and do not
process the files in this directory. Otherwise, continue as
usual. THIS_ROOT might be NULL if we're doing an initial
checkout -- check before using it. The default should be that
we process a directory's contents and only skip those contents
if a CVS/Root file exists.
If we're running the server, we want to process all
directories, since we're guaranteed to have only one CVSROOT --
our own. */
if (
/* If -d was specified, it should override CVS/Root.
In the single-repository case, it is long-standing CVS behavior
and makes sense - the user might want another access method,
another server (which mounts the same repository), &c.
In the multiple-repository case, -d overrides all CVS/Root
files. That is the only plausible generalization I can
think of. */
CVSroot_cmdline == NULL
#ifdef SERVER_SUPPORT
&& ! server_active
#endif
)
{
char *this_root = Name_Root ((char *) NULL, update_dir);
if (this_root != NULL)
{
if (findnode (root_directories, this_root) == NULL)
{
/* Add it to our list. */
Node *n = getnode ();
n->type = UNKNOWN;
n->key = xstrdup (this_root);
if (addnode (root_directories, n))
error (1, 0, "cannot add new CVSROOT %s", this_root);
}
process_this_directory = (strcmp (current_root, this_root) == 0);
free (this_root);
}
}
/*
* Fill in repository with the current repository
*/
@ -468,12 +663,26 @@ do_recursion (frame)
repository = Name_Repository ((char *) NULL, update_dir);
/* find the files and fill in entries if appropriate */
filelist = Find_Names (repository, lwhich, frame->aflag, &entries);
if (process_this_directory)
{
filelist = Find_Names (repository, lwhich, frame->aflag,
&entries);
if (filelist == NULL)
{
error (0, 0, "skipping directory %s", update_dir);
/* Note that Find_Directories and the filesdoneproc
in particular would do bad things ("? foo.c" in
the case of some filesdoneproc's). */
goto skip_directory;
}
}
}
/* find sub-directories if we will recurse */
if (frame->flags != R_SKIP_DIRS)
dirlist = Find_Directories (repository, frame->which, entries);
dirlist = Find_Directories (
process_this_directory ? repository : NULL,
frame->which, entries);
}
else
{
@ -487,7 +696,7 @@ do_recursion (frame)
}
/* process the files (if any) */
if (filelist != NULL && frame->fileproc)
if (process_this_directory && filelist != NULL && frame->fileproc)
{
struct file_info finfo_struct;
struct frame_and_file frfile;
@ -525,11 +734,12 @@ do_recursion (frame)
}
/* call-back files done proc (if any) */
if (dodoneproc && frame->filesdoneproc != NULL)
if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL)
err = frame->filesdoneproc (frame->callerdat, err, repository,
update_dir[0] ? update_dir : ".",
entries);
skip_directory:
fileattr_write ();
fileattr_free ();
@ -589,7 +799,24 @@ do_file_proc (p, closure)
strcat (finfo->fullname, finfo->file);
if (frfile->frame->dosrcs && repository)
{
finfo->rcs = RCS_parse (finfo->file, repository);
/* OK, without W_LOCAL the error handling becomes relatively
simple. The file names came from readdir() on the
repository and so we know any ENOENT is an error
(e.g. symlink pointing to nothing). Now, the logic could
be simpler - since we got the name from readdir, we could
just be calling RCS_parsercsfile. */
if (finfo->rcs == NULL
&& !(frfile->frame->which & W_LOCAL))
{
error (0, 0, "could not read RCS file for %s", finfo->fullname);
free (finfo->fullname);
cvs_flushout ();
return 0;
}
}
else
finfo->rcs = (RCSNode *) NULL;
ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo);
@ -625,6 +852,7 @@ do_dir_proc (p, closure)
int err = 0;
struct saved_cwd cwd;
char *saved_update_dir;
int process_this_directory = 1;
if (fncmp (dir, CVSADM) == 0)
{
@ -760,12 +988,62 @@ but CVS uses %s for its own purposes; skipping %s directory",
free (cvsadmdir);
}
/* Only process this directory if the root matches. This nearly
duplicates code in do_recursion. */
if (
/* If -d was specified, it should override CVS/Root.
In the single-repository case, it is long-standing CVS behavior
and makes sense - the user might want another access method,
another server (which mounts the same repository), &c.
In the multiple-repository case, -d overrides all CVS/Root
files. That is the only plausible generalization I can
think of. */
CVSroot_cmdline == NULL
#ifdef SERVER_SUPPORT
&& ! server_active
#endif
)
{
char *this_root = Name_Root (dir, update_dir);
if (this_root != NULL)
{
if (findnode (root_directories, this_root) == NULL)
{
/* Add it to our list. */
Node *n = getnode ();
n->type = UNKNOWN;
n->key = xstrdup (this_root);
if (addnode (root_directories, n))
error (1, 0, "cannot add new CVSROOT %s", this_root);
}
process_this_directory = (strcmp (current_root, this_root) == 0);
free (this_root);
}
}
/* call-back dir entry proc (if any) */
if (dir_return == R_SKIP_ALL)
;
else if (frame->direntproc != NULL)
dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
update_dir, frent->entries);
{
/* If we're doing the actual processing, call direntproc.
Otherwise, assume that we need to process this directory
and recurse. FIXME. */
if (process_this_directory)
dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
update_dir, frent->entries);
else
dir_return = R_PROCESS;
}
else
{
/* Generic behavior. I don't see a reason to make the caller specify
@ -811,7 +1089,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
(void) strcpy (update_dir, ".");
/* call-back dir leave proc (if any) */
if (frame->dirleaveproc != NULL)
if (process_this_directory && frame->dirleaveproc != NULL)
err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
frent->entries);

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +1,38 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS source distribution.
*
*
* "update" updates the version in the present directory with respect to the RCS
* repository. The present version must have been created by "checkout". The
* user can keep up-to-date by calling "update" whenever he feels like it.
*
*
* The present version can be committed by "commit", but this keeps the version
* in tact.
*
*
* Arguments following the options are taken to be file names to be updated,
* rather than updating the entire directory.
*
*
* Modified or non-existent RCS files are checked out and reported as U
* <user_file>
*
*
* Modified user files are reported as M <user_file>. If both the RCS file and
* the user file have been modified, the user file is replaced by the result
* of rcsmerge, and a backup file is written for the user in .#file.version.
* If this throws up irreconcilable differences, the file is reported as C
* <user_file>, and as M <user_file> otherwise.
*
*
* Files added but not yet committed are reported as A <user_file>. Files
* removed but not yet committed are reported as R <user_file>.
*
*
* If the current directory contains subdirectories that hold concurrent
* versions, these are updated too. If the -d option was specified, new
* directories added to the repository are automatically created and updated
* as well.
*
* $FreeBSD$
*/
#include "cvs.h"
@ -284,11 +286,11 @@ update (argc, argv)
if (failed_patches == NULL)
{
send_file_names (argc, argv, SEND_EXPAND_WILD);
/* If noexec, probably could be setting SEND_NO_CONTENTS.
Same caveats as for "cvs status" apply. */
send_files (argc, argv, local, aflag,
update_build_dirs ? SEND_BUILD_DIRS : 0);
send_file_names (argc, argv, SEND_EXPAND_WILD);
}
else
{
@ -304,10 +306,13 @@ update (argc, argv)
}
for (i = 0; i < failed_patches_count; i++)
(void) unlink_file (failed_patches[i]);
send_file_names (failed_patches_count, failed_patches, 0);
if (unlink_file (failed_patches[i]) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s",
failed_patches[i]);
send_files (failed_patches_count, failed_patches, local,
aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
send_file_names (failed_patches_count, failed_patches, 0);
}
failed_patches = NULL;
@ -486,9 +491,12 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
{
time_t now;
(void) time (&now);
if (now == last_register_time)
for (;;)
{
(void) time (&now);
if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
}
}
return (err);
@ -631,15 +639,7 @@ update_fileproc (callerdat, finfo)
write_letter (finfo, 'C');
break;
case T_NEEDS_MERGE: /* needs merging */
if (noexec)
{
retval = 1;
write_letter (finfo, 'C');
}
else
{
retval = merge_file (finfo, vers);
}
retval = merge_file (finfo, vers);
break;
case T_MODIFIED: /* locally modified */
retval = 0;
@ -874,6 +874,28 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
if (!update_build_dirs)
return (R_SKIP_ALL);
/* Various CVS administrators are in the habit of removing
the repository directory for things they don't want any
more. I've even been known to do it myself (on rare
occasions). Not the usual recommended practice, but we
want to try to come up with some kind of
reasonable/documented/sensible behavior. Generally
the behavior is to just skip over that directory (see
dirs test in sanity.sh; the case which reaches here
is when update -d is specified, and the working directory
is gone but the subdirectory is still mentioned in
CVS/Entries). */
if (1
#ifdef SERVER_SUPPORT
/* In the remote case, the client should refrain from
sending us the directory in the first place. So we
want to continue to give an error, so clients make
sure to do this. */
&& !server_active
#endif
&& !isdir (repository))
return R_SKIP_ALL;
if (noexec)
{
/* ignore the missing dir if -n is specified */
@ -1285,11 +1307,14 @@ VERS: ", 0);
{
Vers_TS *xvers_ts;
if (revbuf != NULL)
if (revbuf != NULL && !noexec)
{
struct stat sb;
/* FIXME: We should have RCS_checkout return the mode. */
/* FIXME: We should have RCS_checkout return the mode.
That would also fix the kludge with noexec, above, which
is here only because noexec doesn't write srcfile->path
for us to stat. */
if (stat (vers_ts->srcfile->path, &sb) < 0)
error (1, errno, "cannot stat %s",
vers_ts->srcfile->path);
@ -1489,7 +1514,7 @@ struct patch_file_data
/* Whether to compute the MD5 checksum. */
int compute_checksum;
/* Data structure for computing the MD5 checksum. */
struct MD5Context context;
struct cvs_MD5Context context;
/* Set if the file has a final newline. */
int final_nl;
};
@ -1568,7 +1593,11 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
if (isfile (finfo->file))
rename_file (finfo->file, backup);
else
(void) unlink_file (backup);
{
if (unlink_file (backup) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", backup);
}
file1 = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
@ -1617,10 +1646,10 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
data.fp = e;
data.final_nl = 0;
data.compute_checksum = 1;
MD5Init (&data.context);
cvs_MD5Init (&data.context);
retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
vers_ts->vn_rcs, (char *) NULL,
vers_ts->vn_rcs, vers_ts->vn_tag,
vers_ts->options, RUN_TTY,
patch_file_write, (void *) &data);
@ -1630,7 +1659,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
if (retcode != 0 || ! data.final_nl)
fail = 1;
else
MD5Final (checksum, &data.context);
cvs_MD5Final (checksum, &data.context);
}
retcode = 0;
@ -1755,9 +1784,15 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
retval = retcode;
}
(void) unlink_file (backup);
(void) unlink_file (file1);
(void) unlink_file (file2);
if (unlink_file (backup) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", backup);
if (unlink_file (file1) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", file1);
if (unlink_file (file2) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", file2);
free (backup);
free (file1);
@ -1783,7 +1818,7 @@ patch_file_write (callerdat, buffer, len)
data->final_nl = (buffer[len - 1] == '\n');
if (data->compute_checksum)
MD5Update (&data->context, (unsigned char *) buffer, len);
cvs_MD5Update (&data->context, (unsigned char *) buffer, len);
}
#endif /* SERVER_SUPPORT */
@ -1859,7 +1894,8 @@ merge_file (finfo, vers)
+ 10);
(void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
(void) unlink_file (backup);
if (unlink_file (backup) && !existence_error (errno))
error (0, errno, "unable to remove %s", backup);
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);
@ -1962,10 +1998,17 @@ merge_file (finfo, vers)
}
#endif
/* 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))
{
printf ("%s already contains the differences between %s and %s\n",
finfo->fullname, vers->vn_user, vers->vn_rcs);
cvs_output (finfo->fullname, 0);
cvs_output (" already contains the differences between ", 0);
cvs_output (vers->vn_user, 0);
cvs_output (" and ", 0);
cvs_output (vers->vn_rcs, 0);
cvs_output ("\n", 1);
history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
finfo->repository);
retval = 0;
@ -1974,8 +2017,7 @@ merge_file (finfo, vers)
if (status == 1)
{
if (!noexec)
error (0, 0, "conflicts found in %s", finfo->fullname);
error (0, 0, "conflicts found in %s", finfo->fullname);
write_letter (finfo, 'C');
@ -2326,7 +2368,9 @@ join_file (finfo, vers)
+ 10);
(void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
(void) unlink_file (backup);
if (unlink_file (backup) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", backup);
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);