summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2008-01-13 06:06:41 +0000
committerobrien <obrien@FreeBSD.org>2008-01-13 06:06:41 +0000
commitc63d336bc91cd291cab752a5688a5967f67ebe78 (patch)
tree1374bf310cddbd3f6245ada6537d535b06a21490 /contrib/cvs/src
parentd2efc9179e584005706bf1f8f4a7c57fee1808c2 (diff)
downloadFreeBSD-src-c63d336bc91cd291cab752a5688a5967f67ebe78.zip
FreeBSD-src-c63d336bc91cd291cab752a5688a5967f67ebe78.tar.gz
Merge rev 1.2 (do not check val-tags if the repository is read-only)
into version 1.11.22.
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r--contrib/cvs/src/tag.c263
1 files changed, 180 insertions, 83 deletions
diff --git a/contrib/cvs/src/tag.c b/contrib/cvs/src/tag.c
index 903f357..43451ce 100644
--- a/contrib/cvs/src/tag.c
+++ b/contrib/cvs/src/tag.c
@@ -1,6 +1,11 @@
/*
- * Copyright (c) 1992, Brian Berliner and Jeff Polk
- * Copyright (c) 1989-1992, Brian Berliner
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions 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.
@@ -152,11 +157,9 @@ cvstag (argc, argv)
break;
case 'Q':
case 'q':
-#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
-#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
cvs_cmd_name);
@@ -354,11 +357,12 @@ rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
{
error (0, errno, "cannot chdir to %s", repository);
free (repository);
+ free (where);
return (1);
}
/* End section which is identical to patch_proc. */
- if (delete_flag || attic_too || (force_tag_match && numtag))
+ if (delete_flag || force_tag_move || attic_too || numtag)
which = W_REPOS | W_ATTIC;
else
which = W_REPOS;
@@ -1134,6 +1138,170 @@ val_fileproc (callerdat, finfo)
+/* This routine determines whether a tag appears in CVSROOT/val-tags.
+ *
+ * The val-tags file will be open read-only when IDB is NULL. Since writes to
+ * val-tags always append to it, the lack of locking is okay. The worst case
+ * race condition might misinterpret a partially written "foobar" matched, for
+ * instance, a request for "f", "foo", of "foob". Such a mismatch would be
+ * caught harmlessly later.
+ *
+ * Before CVS adds a tag to val-tags, it will lock val-tags for write and
+ * verify that the tag is still not present to avoid adding it twice.
+ *
+ * NOTES
+ * This function expects its parent to handle any necessary locking of the
+ * val-tags file.
+ *
+ * INPUTS
+ * idb When this value is NULL, the val-tags file is opened in
+ * in read-only mode. When present, the val-tags file is opened
+ * in read-write mode and the DBM handle is stored in *IDB.
+ * name The tag to search for.
+ *
+ * OUTPUTS
+ * *idb The val-tags file opened for read/write, or NULL if it couldn't
+ * be opened.
+ *
+ * ERRORS
+ * Exits with an error message if the val-tags file cannot be opened for
+ * read (failure to open val-tags read/write is harmless - see below).
+ *
+ * RETURNS
+ * true 1. If NAME exists in val-tags.
+ * 2. If IDB is non-NULL and val-tags cannot be opened for write.
+ * This allows callers to ignore the harmless inability to
+ * update the val-tags cache.
+ * false If the file could be opened and the tag is not present.
+ */
+static int is_in_val_tags PROTO((DBM **idb, const char *name));
+static int
+is_in_val_tags (idb, name)
+ DBM **idb;
+ const char *name;
+{
+ DBM *db = NULL;
+ char *valtags_filename;
+ datum mytag;
+ int status;
+
+ /* Casting out const should be safe here - input datums are not
+ * written to by the myndbm functions.
+ */
+ mytag.dptr = (char *)name;
+ mytag.dsize = strlen (name);
+
+ valtags_filename = xmalloc (strlen (current_parsed_root->directory)
+ + sizeof CVSROOTADM
+ + sizeof CVSROOTADM_VALTAGS + 3);
+ sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_VALTAGS);
+
+ if (idb)
+ {
+ db = dbm_open (valtags_filename, O_RDWR, 0666);
+ if (!db)
+ {
+ mode_t omask;
+
+ if (!existence_error (errno))
+ {
+ error (0, errno, "warning: cannot open %s read/write",
+ valtags_filename);
+ *idb = NULL;
+ return 1;
+ }
+
+ omask = umask (cvsumask);
+ db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ umask (omask);
+ if (!db)
+ {
+ error (0, errno, "warning: cannot create %s",
+ valtags_filename);
+ *idb = NULL;
+ return 1;
+ }
+
+ *idb = db;
+ return 0;
+ }
+
+ *idb = db;
+ }
+ else
+ {
+ db = dbm_open (valtags_filename, O_RDONLY, 0444);
+ if (!db && !existence_error (errno))
+ error (1, errno, "cannot read %s", valtags_filename);
+ }
+
+ /* If the file merely fails to exist, we just keep going and create
+ it later if need be. */
+
+ status = 0;
+ if (db)
+ {
+ datum val;
+
+ val = dbm_fetch (db, mytag);
+ if (val.dptr != NULL)
+ /* Found. The tag is valid. */
+ status = 1;
+
+ /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
+
+ if (!idb) dbm_close (db);
+ }
+
+ free (valtags_filename);
+ return status;
+}
+
+
+
+/* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and
+ * reverifies that the tag does not exist before adding it.
+ */
+static void add_to_val_tags PROTO((const char *name));
+static void
+add_to_val_tags (name)
+ const char *name;
+{
+ DBM *db;
+ datum mytag;
+ datum value;
+
+ if (noexec) return;
+
+ val_tags_lock (current_parsed_root->directory);
+
+ /* Check for presence again since we have a lock now. */
+ if (is_in_val_tags (&db, name))
+ {
+ clear_val_tags_lock ();
+ if (db)
+ dbm_close (db);
+ return;
+ }
+
+ /* Casting out const should be safe here - input datums are not
+ * written to by the myndbm functions.
+ */
+ mytag.dptr = (char *)name;
+ mytag.dsize = strlen (name);
+ value.dptr = "y";
+ value.dsize = 1;
+
+ if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
+ error (0, errno, "failed to store %s into val-tags", name);
+ dbm_close (db);
+
+ clear_val_tags_lock ();
+}
+
+
+
static Dtype val_direntproc PROTO ((void *, const char *, const char *,
const char *, List *));
@@ -1175,10 +1343,6 @@ tag_check_valid (name, argc, argv, local, aflag, repository)
int aflag;
char *repository;
{
- DBM *db;
- char *valtags_filename;
- int nowrite = 0;
- datum mytag;
struct val_args the_val_args;
struct saved_cwd cwd;
int which;
@@ -1204,49 +1368,12 @@ Numeric tag %s contains characters other than digits and '.'", name);
if (readonlyfs)
return;
- /* FIXME: This routine doesn't seem to do any locking whatsoever
- (and it is called from places which don't have locks in place).
- If two processes try to write val-tags at the same time, it would
- seem like we are in trouble. */
-
- mytag.dptr = name;
- mytag.dsize = strlen (name);
-
- valtags_filename = xmalloc (strlen (current_parsed_root->directory)
- + sizeof CVSROOTADM
- + sizeof CVSROOTADM_VALTAGS + 3);
- sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
- CVSROOTADM, CVSROOTADM_VALTAGS);
- db = dbm_open (valtags_filename, O_RDWR, 0666);
- if (db == NULL)
- {
- if (!existence_error (errno))
- {
- error (0, errno, "warning: cannot open %s read/write",
- valtags_filename);
- db = dbm_open (valtags_filename, O_RDONLY, 0666);
- if (db != NULL)
- nowrite = 1;
- else if (!existence_error (errno))
- error (1, errno, "cannot read %s", valtags_filename);
- }
- /* If the file merely fails to exist, we just keep going and create
- it later if need be. */
- }
- if (db != NULL)
- {
- datum val;
+ /* Verify that the tag is valid syntactically. Some later code once made
+ * assumptions about this.
+ */
+ RCS_check_tag (name);
- val = dbm_fetch (db, mytag);
- if (val.dptr != NULL)
- {
- /* Found. The tag is valid. */
- dbm_close (db);
- free (valtags_filename);
- return;
- }
- /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
- }
+ if (is_in_val_tags (NULL, name)) return;
/* We didn't find the tag in val-tags, so look through all the RCS files
to see whether it exists there. Yes, this is expensive, but there
@@ -1291,41 +1418,11 @@ Numeric tag %s contains characters other than digits and '.'", name);
if (!the_val_args.found)
error (1, 0, "no such tag %s", name);
else
- {
/* The tags is valid but not mentioned in val-tags. Add it. */
- datum value;
+ add_to_val_tags (name);
+}
- if (noexec || nowrite)
- {
- if (db != NULL)
- dbm_close (db);
- free (valtags_filename);
- return;
- }
- if (db == NULL)
- {
- mode_t omask;
- omask = umask (cvsumask);
- db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
- (void)umask (omask);
-
- if (db == NULL)
- {
- error (0, errno, "warning: cannot create %s", valtags_filename);
- free (valtags_filename);
- return;
- }
- }
- value.dptr = "y";
- value.dsize = 1;
- if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
- error (0, errno, "cannot store %s into %s", name,
- valtags_filename);
- dbm_close (db);
- }
- free (valtags_filename);
-}
/*
* Check whether a join tag is valid. This is just like
OpenPOWER on IntegriCloud