Merge rev 1.2 (do not check val-tags if the repository is read-only)

into version 1.11.22.
This commit is contained in:
David E. O'Brien 2008-01-13 06:06:41 +00:00
parent 5508baed23
commit d304d2a774

View File

@ -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. */
/* Verify that the tag is valid syntactically. Some later code once made
* assumptions about this.
*/
RCS_check_tag (name);
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;
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,42 +1418,12 @@ 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;
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);
add_to_val_tags (name);
}
/*
* Check whether a join tag is valid. This is just like
* tag_check_valid, but we must stop before the colon if there is one.