Merge cyclic changes for 1.10.7 only our mainline.
This commit is contained in:
parent
c17d50044b
commit
9bd45385bc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=54431
@ -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
|
||||
*/
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user