| 1 |
/* |
/* |
| 2 |
* Copyright (c) 1992, Brian Berliner and Jeff Polk |
* Copyright (C) 1986-2005 The Free Software Foundation, Inc. |
| 3 |
* Copyright (c) 1989-1992, Brian Berliner |
* |
| 4 |
|
* Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, |
| 5 |
|
* and others. |
| 6 |
|
* |
| 7 |
|
* Portions Copyright (C) 1992, Brian Berliner and Jeff Polk |
| 8 |
|
* Portions Copyright (C) 1989-1992, Brian Berliner |
| 9 |
* |
* |
| 10 |
* You may distribute under the terms of the GNU General Public License as |
* You may distribute under the terms of the GNU General Public License as |
| 11 |
* specified in the README file that comes with the CVS source distribution. |
* specified in the README file that comes with the CVS source distribution. |
| 155 |
break; |
break; |
| 156 |
case 'Q': |
case 'Q': |
| 157 |
case 'q': |
case 'q': |
|
#ifdef SERVER_SUPPORT |
|
| 158 |
/* The CVS 1.5 client sends these options (in addition to |
/* The CVS 1.5 client sends these options (in addition to |
| 159 |
Global_option requests), so we must ignore them. */ |
Global_option requests), so we must ignore them. */ |
| 160 |
if (!server_active) |
if (!server_active) |
|
#endif |
|
| 161 |
error (1, 0, |
error (1, 0, |
| 162 |
"-q or -Q must be specified before \"%s\"", |
"-q or -Q must be specified before \"%s\"", |
| 163 |
cvs_cmd_name); |
cvs_cmd_name); |
| 355 |
{ |
{ |
| 356 |
error (0, errno, "cannot chdir to %s", repository); |
error (0, errno, "cannot chdir to %s", repository); |
| 357 |
free (repository); |
free (repository); |
| 358 |
|
free (where); |
| 359 |
return (1); |
return (1); |
| 360 |
} |
} |
| 361 |
/* End section which is identical to patch_proc. */ |
/* End section which is identical to patch_proc. */ |
| 362 |
|
|
| 363 |
if (delete_flag || attic_too || (force_tag_match && numtag)) |
if (delete_flag || force_tag_move || attic_too || numtag) |
| 364 |
which = W_REPOS | W_ATTIC; |
which = W_REPOS | W_ATTIC; |
| 365 |
else |
else |
| 366 |
which = W_REPOS; |
which = W_REPOS; |
| 1136 |
|
|
| 1137 |
|
|
| 1138 |
|
|
| 1139 |
|
/* This routine determines whether a tag appears in CVSROOT/val-tags. |
| 1140 |
|
* |
| 1141 |
|
* The val-tags file will be open read-only when IDB is NULL. Since writes to |
| 1142 |
|
* val-tags always append to it, the lack of locking is okay. The worst case |
| 1143 |
|
* race condition might misinterpret a partially written "foobar" matched, for |
| 1144 |
|
* instance, a request for "f", "foo", of "foob". Such a mismatch would be |
| 1145 |
|
* caught harmlessly later. |
| 1146 |
|
* |
| 1147 |
|
* Before CVS adds a tag to val-tags, it will lock val-tags for write and |
| 1148 |
|
* verify that the tag is still not present to avoid adding it twice. |
| 1149 |
|
* |
| 1150 |
|
* NOTES |
| 1151 |
|
* This function expects its parent to handle any necessary locking of the |
| 1152 |
|
* val-tags file. |
| 1153 |
|
* |
| 1154 |
|
* INPUTS |
| 1155 |
|
* idb When this value is NULL, the val-tags file is opened in |
| 1156 |
|
* in read-only mode. When present, the val-tags file is opened |
| 1157 |
|
* in read-write mode and the DBM handle is stored in *IDB. |
| 1158 |
|
* name The tag to search for. |
| 1159 |
|
* |
| 1160 |
|
* OUTPUTS |
| 1161 |
|
* *idb The val-tags file opened for read/write, or NULL if it couldn't |
| 1162 |
|
* be opened. |
| 1163 |
|
* |
| 1164 |
|
* ERRORS |
| 1165 |
|
* Exits with an error message if the val-tags file cannot be opened for |
| 1166 |
|
* read (failure to open val-tags read/write is harmless - see below). |
| 1167 |
|
* |
| 1168 |
|
* RETURNS |
| 1169 |
|
* true 1. If NAME exists in val-tags. |
| 1170 |
|
* 2. If IDB is non-NULL and val-tags cannot be opened for write. |
| 1171 |
|
* This allows callers to ignore the harmless inability to |
| 1172 |
|
* update the val-tags cache. |
| 1173 |
|
* false If the file could be opened and the tag is not present. |
| 1174 |
|
*/ |
| 1175 |
|
static int is_in_val_tags PROTO((DBM **idb, const char *name)); |
| 1176 |
|
static int |
| 1177 |
|
is_in_val_tags (idb, name) |
| 1178 |
|
DBM **idb; |
| 1179 |
|
const char *name; |
| 1180 |
|
{ |
| 1181 |
|
DBM *db = NULL; |
| 1182 |
|
char *valtags_filename; |
| 1183 |
|
datum mytag; |
| 1184 |
|
int status; |
| 1185 |
|
|
| 1186 |
|
/* Casting out const should be safe here - input datums are not |
| 1187 |
|
* written to by the myndbm functions. |
| 1188 |
|
*/ |
| 1189 |
|
mytag.dptr = (char *)name; |
| 1190 |
|
mytag.dsize = strlen (name); |
| 1191 |
|
|
| 1192 |
|
valtags_filename = xmalloc (strlen (current_parsed_root->directory) |
| 1193 |
|
+ sizeof CVSROOTADM |
| 1194 |
|
+ sizeof CVSROOTADM_VALTAGS + 3); |
| 1195 |
|
sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory, |
| 1196 |
|
CVSROOTADM, CVSROOTADM_VALTAGS); |
| 1197 |
|
|
| 1198 |
|
if (idb) |
| 1199 |
|
{ |
| 1200 |
|
db = dbm_open (valtags_filename, O_RDWR, 0666); |
| 1201 |
|
if (!db) |
| 1202 |
|
{ |
| 1203 |
|
mode_t omask; |
| 1204 |
|
|
| 1205 |
|
if (!existence_error (errno)) |
| 1206 |
|
{ |
| 1207 |
|
error (0, errno, "warning: cannot open %s read/write", |
| 1208 |
|
valtags_filename); |
| 1209 |
|
*idb = NULL; |
| 1210 |
|
return 1; |
| 1211 |
|
} |
| 1212 |
|
|
| 1213 |
|
omask = umask (cvsumask); |
| 1214 |
|
db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666); |
| 1215 |
|
umask (omask); |
| 1216 |
|
if (!db) |
| 1217 |
|
{ |
| 1218 |
|
error (0, errno, "warning: cannot create %s", |
| 1219 |
|
valtags_filename); |
| 1220 |
|
*idb = NULL; |
| 1221 |
|
return 1; |
| 1222 |
|
} |
| 1223 |
|
|
| 1224 |
|
*idb = db; |
| 1225 |
|
return 0; |
| 1226 |
|
} |
| 1227 |
|
|
| 1228 |
|
*idb = db; |
| 1229 |
|
} |
| 1230 |
|
else |
| 1231 |
|
{ |
| 1232 |
|
db = dbm_open (valtags_filename, O_RDONLY, 0444); |
| 1233 |
|
if (!db && !existence_error (errno)) |
| 1234 |
|
error (1, errno, "cannot read %s", valtags_filename); |
| 1235 |
|
} |
| 1236 |
|
|
| 1237 |
|
/* If the file merely fails to exist, we just keep going and create |
| 1238 |
|
it later if need be. */ |
| 1239 |
|
|
| 1240 |
|
status = 0; |
| 1241 |
|
if (db) |
| 1242 |
|
{ |
| 1243 |
|
datum val; |
| 1244 |
|
|
| 1245 |
|
val = dbm_fetch (db, mytag); |
| 1246 |
|
if (val.dptr != NULL) |
| 1247 |
|
/* Found. The tag is valid. */ |
| 1248 |
|
status = 1; |
| 1249 |
|
|
| 1250 |
|
/* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */ |
| 1251 |
|
|
| 1252 |
|
if (!idb) dbm_close (db); |
| 1253 |
|
} |
| 1254 |
|
|
| 1255 |
|
free (valtags_filename); |
| 1256 |
|
return status; |
| 1257 |
|
} |
| 1258 |
|
|
| 1259 |
|
|
| 1260 |
|
|
| 1261 |
|
/* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and |
| 1262 |
|
* reverifies that the tag does not exist before adding it. |
| 1263 |
|
*/ |
| 1264 |
|
static void add_to_val_tags PROTO((const char *name)); |
| 1265 |
|
static void |
| 1266 |
|
add_to_val_tags (name) |
| 1267 |
|
const char *name; |
| 1268 |
|
{ |
| 1269 |
|
DBM *db; |
| 1270 |
|
datum mytag; |
| 1271 |
|
datum value; |
| 1272 |
|
|
| 1273 |
|
if (noexec) return; |
| 1274 |
|
|
| 1275 |
|
val_tags_lock (current_parsed_root->directory); |
| 1276 |
|
|
| 1277 |
|
/* Check for presence again since we have a lock now. */ |
| 1278 |
|
if (is_in_val_tags (&db, name)) |
| 1279 |
|
{ |
| 1280 |
|
clear_val_tags_lock (); |
| 1281 |
|
if (db) |
| 1282 |
|
dbm_close (db); |
| 1283 |
|
return; |
| 1284 |
|
} |
| 1285 |
|
|
| 1286 |
|
/* Casting out const should be safe here - input datums are not |
| 1287 |
|
* written to by the myndbm functions. |
| 1288 |
|
*/ |
| 1289 |
|
mytag.dptr = (char *)name; |
| 1290 |
|
mytag.dsize = strlen (name); |
| 1291 |
|
value.dptr = "y"; |
| 1292 |
|
value.dsize = 1; |
| 1293 |
|
|
| 1294 |
|
if (dbm_store (db, mytag, value, DBM_REPLACE) < 0) |
| 1295 |
|
error (0, errno, "failed to store %s into val-tags", name); |
| 1296 |
|
dbm_close (db); |
| 1297 |
|
|
| 1298 |
|
clear_val_tags_lock (); |
| 1299 |
|
} |
| 1300 |
|
|
| 1301 |
|
|
| 1302 |
|
|
| 1303 |
static Dtype val_direntproc PROTO ((void *, const char *, const char *, |
static Dtype val_direntproc PROTO ((void *, const char *, const char *, |
| 1304 |
const char *, List *)); |
const char *, List *)); |
| 1305 |
|
|
| 1341 |
int aflag; |
int aflag; |
| 1342 |
char *repository; |
char *repository; |
| 1343 |
{ |
{ |
|
DBM *db; |
|
|
char *valtags_filename; |
|
|
int nowrite = 0; |
|
|
datum mytag; |
|
| 1344 |
struct val_args the_val_args; |
struct val_args the_val_args; |
| 1345 |
struct saved_cwd cwd; |
struct saved_cwd cwd; |
| 1346 |
int which; |
int which; |
| 1363 |
|| strcmp (name, TAG_HEAD) == 0) |
|| strcmp (name, TAG_HEAD) == 0) |
| 1364 |
return; |
return; |
| 1365 |
|
|
| 1366 |
/* FIXME: This routine doesn't seem to do any locking whatsoever |
/* Verify that the tag is valid syntactically. Some later code once made |
| 1367 |
(and it is called from places which don't have locks in place). |
* assumptions about this. |
| 1368 |
If two processes try to write val-tags at the same time, it would |
*/ |
| 1369 |
seem like we are in trouble. */ |
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; |
|
| 1370 |
|
|
| 1371 |
val = dbm_fetch (db, mytag); |
if (is_in_val_tags (NULL, name)) return; |
|
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?). */ |
|
|
} |
|
| 1372 |
|
|
| 1373 |
/* We didn't find the tag in val-tags, so look through all the RCS files |
/* We didn't find the tag in val-tags, so look through all the RCS files |
| 1374 |
to see whether it exists there. Yes, this is expensive, but there |
to see whether it exists there. Yes, this is expensive, but there |
| 1413 |
if (!the_val_args.found) |
if (!the_val_args.found) |
| 1414 |
error (1, 0, "no such tag %s", name); |
error (1, 0, "no such tag %s", name); |
| 1415 |
else |
else |
|
{ |
|
| 1416 |
/* The tags is valid but not mentioned in val-tags. Add it. */ |
/* The tags is valid but not mentioned in val-tags. Add it. */ |
| 1417 |
datum value; |
add_to_val_tags (name); |
|
|
|
|
if (noexec || nowrite) |
|
|
{ |
|
|
if (db != NULL) |
|
|
dbm_close (db); |
|
|
free (valtags_filename); |
|
|
return; |
|
| 1418 |
} |
} |
| 1419 |
|
|
|
if (db == NULL) |
|
|
{ |
|
|
mode_t omask; |
|
|
omask = umask (cvsumask); |
|
|
db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666); |
|
|
(void)umask (omask); |
|
| 1420 |
|
|
|
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); |
|
|
} |
|
| 1421 |
|
|
| 1422 |
/* |
/* |
| 1423 |
* Check whether a join tag is valid. This is just like |
* Check whether a join tag is valid. This is just like |