diff options
author | obrien <obrien@FreeBSD.org> | 2008-01-13 06:06:41 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2008-01-13 06:06:41 +0000 |
commit | c63d336bc91cd291cab752a5688a5967f67ebe78 (patch) | |
tree | 1374bf310cddbd3f6245ada6537d535b06a21490 /contrib/cvs | |
parent | d2efc9179e584005706bf1f8f4a7c57fee1808c2 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | contrib/cvs/src/tag.c | 263 |
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 |