summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/commit.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/commit.c')
-rw-r--r--contrib/cvs/src/commit.c287
1 files changed, 172 insertions, 115 deletions
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index c4cbd24..6b674e1 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -12,6 +12,7 @@
*
* The call is: cvs commit [options] files...
*
+ * $FreeBSD$
*/
#include <assert.h>
@@ -49,6 +50,7 @@ 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));
@@ -340,11 +342,10 @@ 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
- /* Who we are on the client side doesn't affect logging. */
+#ifdef CLIENT_SUPPORT
&& !client_active
-# endif
- )
+#endif
+ )
{
struct passwd *pw;
@@ -410,7 +411,7 @@ commit (argc, argv)
argv += optind;
/* numeric specified revision means we ignore sticky tags... */
- if (saved_tag && isdigit ((unsigned char) *saved_tag))
+ if (saved_tag && isdigit (*saved_tag))
{
aflag = 1;
/* strip trailing dots */
@@ -509,7 +510,7 @@ commit (argc, argv)
/* Run the user-defined script to verify/check information in
*the log message
*/
- do_verify (saved_message, (char *)NULL);
+ do_verify (&saved_message, (char *)NULL);
/* We always send some sort of message, even if empty. */
/* FIXME: is that true? There seems to be some code in do_editor
@@ -565,6 +566,13 @@ 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
@@ -577,13 +585,6 @@ 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)
@@ -676,10 +677,9 @@ commit (argc, argv)
{
time_t now;
- for (;;)
+ (void) time (&now);
+ if (now == last_register_time)
{
- (void) time (&now);
- if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
}
}
@@ -708,7 +708,7 @@ classify_file_internal (finfo, vers)
noexec = quiet = really_quiet = 1;
/* handle specified numeric revision specially */
- if (saved_tag && isdigit ((unsigned char) *saved_tag))
+ if (saved_tag && isdigit (*saved_tag))
{
/* If the tag is for the trunk, make sure we're at the head */
if (numdots (saved_tag) < 2)
@@ -792,19 +792,6 @@ 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);
/*
@@ -843,7 +830,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 ((unsigned char) *saved_tag))
+ if (!saved_tag || !isdigit (*saved_tag))
{
if (vers->date)
{
@@ -915,9 +902,7 @@ warning: file `%s' seems to still contain conflict indicators",
}
}
- if (status == T_REMOVED
- && vers->tag
- && isdigit ((unsigned char) *vers->tag))
+ if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
{
/* Remove also tries to forbid this, but we should check
here. I'm only _sure_ about somewhat obscure cases
@@ -956,7 +941,7 @@ warning: file `%s' seems to still contain conflict indicators",
}
free (rcs);
}
- if (vers->tag && isdigit ((unsigned char) *vers->tag) &&
+ if (vers->tag && isdigit (*vers->tag) &&
numdots (vers->tag) > 1)
{
error (0, 0,
@@ -1016,7 +1001,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 ((unsigned char) *vers->tag))
+ if (isdigit (*vers->tag))
ci->rev = xstrdup (vers->tag);
else
ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
@@ -1135,7 +1120,7 @@ precommit_proc (repository, filter)
s = xstrdup (filter);
for (cp = s; *cp; cp++)
- if (isspace ((unsigned char) *cp))
+ if (isspace (*cp))
{
*cp = '\0';
break;
@@ -1248,7 +1233,7 @@ commit_fileproc (callerdat, finfo)
if (use_editor)
do_editor (finfo->update_dir, &saved_message,
finfo->repository, ulist);
- do_verify (saved_message, finfo->repository);
+ do_verify (&saved_message, finfo->repository);
}
p = findnode (cilist, finfo->file);
@@ -1282,11 +1267,7 @@ 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 numeric, it is on the trunk; check_fileproc enforced
- this. */
- && !isdigit ((unsigned char) ci->tag[0]))
+ if (ci->tag)
{
if (finfo->rcs == NULL)
error (1, 0, "internal error: no parsed RCS file");
@@ -1559,7 +1540,7 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
got_message = 1;
if (use_editor)
do_editor (update_dir, &saved_message, real_repos, ulist);
- do_verify (saved_message, real_repos);
+ do_verify (&saved_message, real_repos);
free (real_repos);
return (R_PROCESS);
}
@@ -1620,16 +1601,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;
@@ -1719,6 +1700,16 @@ 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,
@@ -1755,9 +1746,34 @@ remove_file (finfo, tag, message)
if (rev != NULL)
free (rev);
- old_path = xstrdup (finfo->rcs->path);
+ old_path = finfo->rcs->path;
if (!branch)
- RCS_setattic (finfo->rcs, 1);
+ {
+ /* 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;
+ }
/* Print message that file was removed. */
cvs_output (old_path, 0);
@@ -1768,7 +1784,8 @@ remove_file (finfo, tag, message)
cvs_output ("\ndone\n", 0);
free(prev_rev);
- free (old_path);
+ if (old_path != finfo->rcs->path)
+ free (old_path);
Scratch_Entry (finfo->entries, finfo->file);
return (0);
@@ -1794,9 +1811,7 @@ 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);
- if (unlink_file (tmp) < 0
- && !existence_error (errno))
- error (0, errno, "cannot remove %s", tmp);
+ (void) unlink_file (tmp);
free (tmp);
}
else
@@ -1840,10 +1855,7 @@ fixaddfile (file, repository)
save_really_quiet = really_quiet;
really_quiet = 1;
if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
- {
- if (unlink_file (rcs) < 0)
- error (0, errno, "cannot remove %s", rcs);
- }
+ (void) unlink_file (rcs);
else
freercsnode (&rcsfile);
really_quiet = save_really_quiet;
@@ -1890,20 +1902,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
int newfile = 0;
RCSNode *rcsfile = NULL;
int retval;
- int adding_on_branch;
-
- /* 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)
+ if (tag)
{
rcs = xmalloc (strlen (repository) + strlen (file)
+ sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
@@ -1926,7 +1926,6 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
/* file has existed in the past. Prepare to resurrect. */
char *rev;
- char *oldexpand;
if ((rcsfile = *rcsnode) == NULL)
{
@@ -1935,38 +1934,41 @@ checkaddfile (file, repository, tag, options, rcsnode)
goto out;
}
- oldexpand = RCS_getexpand (rcsfile);
- if ((oldexpand != NULL
- && options != NULL
- && strcmp (options + 2, oldexpand) != 0)
- || (oldexpand == NULL && options != NULL))
+ if (tag == NULL)
{
- /* We tell the user about this, because it means that the
- old revisions will no longer retrieve the way that they
- used to. */
- error (0, 0, "changing keyword expansion mode to %s", options);
- RCS_setexpand (rcsfile, options + 2);
- }
+ char *oldfile;
- if (!adding_on_branch)
- {
- /* We are adding on the trunk, so move the file out of the
- Attic. */
- if (!(rcsfile->flags & INATTIC))
+ /* 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)
{
error (0, 0, "internal error: confused about attic for %s",
- rcsfile->path);
+ oldfile);
+ out1:
+ free (oldfile);
retval = 1;
goto out;
}
-
- sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
-
- if (RCS_setattic (rcsfile, 0))
+ if (CVS_RENAME (oldfile, rcs) != 0)
{
- retval = 1;
- goto out;
+ error (0, errno, "failed to move `%s' out of the attic",
+ oldfile);
+ goto out1;
}
+ 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);
@@ -2019,7 +2021,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
}
/* Set RCS keyword expansion options. */
- if (options != NULL)
+ if (options && options[0] == '-' && options[1] == 'k')
opt = options + 2;
else
opt = NULL;
@@ -2048,7 +2050,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
/* when adding a file for the first time, and using a tag, we need
to create a dead revision on the trunk. */
- if (adding_on_branch && newfile)
+ if (tag && newfile)
{
char *tmp;
FILE *fp;
@@ -2110,7 +2112,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
}
}
- if (adding_on_branch)
+ if (tag != NULL)
{
/* when adding with a tag, we need to stub a branch, if it
doesn't already exist. */
@@ -2137,6 +2139,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
char *head;
char *magicrev;
+ fixbranch(rcsfile, sbranch);
+
head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
magicrev = RCS_magicrev (rcsfile, head);
@@ -2174,22 +2178,13 @@ checkaddfile (file, repository, tag, options, rcsnode)
fileattr_newfile (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. */
+ /* 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);
retval = 0;
@@ -2223,8 +2218,7 @@ 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 ((unsigned char) *rev) && numdots (rev) < 2))
+ if (rev == NULL || (rev && isdigit (*rev) && numdots (rev) < 2))
{
branch = xstrdup (rcs->branch);
if (branch != NULL)
@@ -2281,6 +2275,69 @@ 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
*/
OpenPOWER on IntegriCloud