xref: /illumos-gate/usr/src/cmd/sendmail/db/db/db_iface.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997, 1998
5  *	Sleepycat Software.  All rights reserved.
6  */
7 
8 #include "config.h"
9 
10 #ifndef lint
11 static const char sccsid[] = "@(#)db_iface.c	10.40 (Sleepycat) 12/19/98";
12 #endif /* not lint */
13 
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16 
17 #include <errno.h>
18 #endif
19 
20 #include "db_int.h"
21 #include "db_page.h"
22 #include "db_auto.h"
23 #include "db_ext.h"
24 #include "common_ext.h"
25 
26 static int __db_keyempty __P((const DB_ENV *));
27 static int __db_rdonly __P((const DB_ENV *, const char *));
28 static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));
29 
30 /*
31  * __db_cdelchk --
32  *	Common cursor delete argument checking routine.
33  *
34  * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int));
35  */
36 int
__db_cdelchk(dbp,flags,isrdonly,isvalid)37 __db_cdelchk(dbp, flags, isrdonly, isvalid)
38 	const DB *dbp;
39 	u_int32_t flags;
40 	int isrdonly, isvalid;
41 {
42 	/* Check for changes to a read-only tree. */
43 	if (isrdonly)
44 		return (__db_rdonly(dbp->dbenv, "c_del"));
45 
46 	/* Check for invalid function flags. */
47 	switch (flags) {
48 	case 0:
49 		break;
50 	default:
51 		return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0));
52 	}
53 
54 	/*
55 	 * The cursor must be initialized, return -1 for an invalid cursor,
56 	 * otherwise 0.
57 	 */
58 	return (isvalid ? 0 : EINVAL);
59 }
60 
61 /*
62  * __db_cgetchk --
63  *	Common cursor get argument checking routine.
64  *
65  * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
66  */
67 int
__db_cgetchk(dbp,key,data,flags,isvalid)68 __db_cgetchk(dbp, key, data, flags, isvalid)
69 	const DB *dbp;
70 	DBT *key, *data;
71 	u_int32_t flags;
72 	int isvalid;
73 {
74 	int key_einval, key_flags, ret;
75 
76 	key_einval = key_flags = 0;
77 
78 	/* Check for invalid function flags. */
79 	LF_CLR(DB_RMW);
80 	switch (flags) {
81 	case DB_NEXT_DUP:
82 		if (dbp->type == DB_RECNO)
83 			goto err;
84 		/* FALLTHROUGH */
85 	case DB_CURRENT:
86 	case DB_FIRST:
87 	case DB_LAST:
88 	case DB_NEXT:
89 	case DB_PREV:
90 		key_flags = 1;
91 		break;
92 	case DB_GET_BOTH:
93 	case DB_SET_RANGE:
94 		key_einval = key_flags = 1;
95 		break;
96 	case DB_SET:
97 		key_einval = 1;
98 		break;
99 	case DB_GET_RECNO:
100 		if (!F_ISSET(dbp, DB_BT_RECNUM))
101 			goto err;
102 		break;
103 	case DB_SET_RECNO:
104 		if (!F_ISSET(dbp, DB_BT_RECNUM))
105 			goto err;
106 		key_einval = key_flags = 1;
107 		break;
108 	default:
109 err:		return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
110 	}
111 
112 	/* Check for invalid key/data flags. */
113 	if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
114 		return (ret);
115 	if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
116 		return (ret);
117 
118 	/* Check for missing keys. */
119 	if (key_einval && (key->data == NULL || key->size == 0))
120 		return (__db_keyempty(dbp->dbenv));
121 
122 	/*
123 	 * The cursor must be initialized for DB_CURRENT, return -1 for an
124 	 * invalid cursor, otherwise 0.
125 	 */
126 	return (isvalid || flags != DB_CURRENT ? 0 : EINVAL);
127 }
128 
129 /*
130  * __db_cputchk --
131  *	Common cursor put argument checking routine.
132  *
133  * PUBLIC: int __db_cputchk __P((const DB *,
134  * PUBLIC:    const DBT *, DBT *, u_int32_t, int, int));
135  */
136 int
__db_cputchk(dbp,key,data,flags,isrdonly,isvalid)137 __db_cputchk(dbp, key, data, flags, isrdonly, isvalid)
138 	const DB *dbp;
139 	const DBT *key;
140 	DBT *data;
141 	u_int32_t flags;
142 	int isrdonly, isvalid;
143 {
144 	int key_einval, key_flags, ret;
145 
146 	key_einval = key_flags = 0;
147 
148 	/* Check for changes to a read-only tree. */
149 	if (isrdonly)
150 		return (__db_rdonly(dbp->dbenv, "c_put"));
151 
152 	/* Check for invalid function flags. */
153 	switch (flags) {
154 	case DB_AFTER:
155 	case DB_BEFORE:
156 		if (dbp->dup_compare != NULL)
157 			goto err;
158 		if (dbp->type == DB_RECNO && !F_ISSET(dbp, DB_RE_RENUMBER))
159 			goto err;
160 		if (dbp->type != DB_RECNO && !F_ISSET(dbp, DB_AM_DUP))
161 			goto err;
162 		break;
163 	case DB_CURRENT:
164 		/*
165 		 * If there is a comparison function, doing a DB_CURRENT
166 		 * must not change the part of the data item that is used
167 		 * for the comparison.
168 		 */
169 		break;
170 	case DB_KEYFIRST:
171 	case DB_KEYLAST:
172 		if (dbp->type == DB_RECNO)
173 			goto err;
174 		key_einval = key_flags = 1;
175 		break;
176 	default:
177 err:		return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0));
178 	}
179 
180 	/* Check for invalid key/data flags. */
181 	if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
182 		return (ret);
183 	if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
184 		return (ret);
185 
186 	/* Check for missing keys. */
187 	if (key_einval && (key->data == NULL || key->size == 0))
188 		return (__db_keyempty(dbp->dbenv));
189 
190 	/*
191 	 * The cursor must be initialized for anything other than DB_KEYFIRST
192 	 * and DB_KEYLAST, return -1 for an invalid cursor, otherwise 0.
193 	 */
194 	return (isvalid ||
195 	    flags == DB_KEYFIRST || flags == DB_KEYLAST ? 0 : EINVAL);
196 }
197 
198 /*
199  * __db_closechk --
200  *	DB->close flag check.
201  *
202  * PUBLIC: int __db_closechk __P((const DB *, u_int32_t));
203  */
204 int
__db_closechk(dbp,flags)205 __db_closechk(dbp, flags)
206 	const DB *dbp;
207 	u_int32_t flags;
208 {
209 	/* Check for invalid function flags. */
210 	if (flags != 0 && flags != DB_NOSYNC)
211 		return (__db_ferr(dbp->dbenv, "DB->close", 0));
212 
213 	return (0);
214 }
215 
216 /*
217  * __db_delchk --
218  *	Common delete argument checking routine.
219  *
220  * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
221  */
222 int
__db_delchk(dbp,key,flags,isrdonly)223 __db_delchk(dbp, key, flags, isrdonly)
224 	const DB *dbp;
225 	DBT *key;
226 	u_int32_t flags;
227 	int isrdonly;
228 {
229 	/* Check for changes to a read-only tree. */
230 	if (isrdonly)
231 		return (__db_rdonly(dbp->dbenv, "delete"));
232 
233 	/* Check for invalid function flags. */
234 	switch (flags) {
235 	case 0:
236 		break;
237 	default:
238 		return (__db_ferr(dbp->dbenv, "DB->del", 0));
239 	}
240 
241 	/* Check for missing keys. */
242 	if (key->data == NULL || key->size == 0)
243 		return (__db_keyempty(dbp->dbenv));
244 
245 	return (0);
246 }
247 
248 /*
249  * __db_getchk --
250  *	Common get argument checking routine.
251  *
252  * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
253  */
254 int
__db_getchk(dbp,key,data,flags)255 __db_getchk(dbp, key, data, flags)
256 	const DB *dbp;
257 	const DBT *key;
258 	DBT *data;
259 	u_int32_t flags;
260 {
261 	int ret;
262 
263 	/* Check for invalid function flags. */
264 	LF_CLR(DB_RMW);
265 	switch (flags) {
266 	case 0:
267 	case DB_GET_BOTH:
268 		break;
269 	case DB_SET_RECNO:
270 		if (!F_ISSET(dbp, DB_BT_RECNUM))
271 			goto err;
272 		break;
273 	default:
274 err:		return (__db_ferr(dbp->dbenv, "DB->get", 0));
275 	}
276 
277 	/* Check for invalid key/data flags. */
278 	if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0)
279 		return (ret);
280 	if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0)
281 		return (ret);
282 
283 	/* Check for missing keys. */
284 	if (key->data == NULL || key->size == 0)
285 		return (__db_keyempty(dbp->dbenv));
286 
287 	return (0);
288 }
289 
290 /*
291  * __db_joinchk --
292  *	Common join argument checking routine.
293  *
294  * PUBLIC: int __db_joinchk __P((const DB *, u_int32_t));
295  */
296 int
__db_joinchk(dbp,flags)297 __db_joinchk(dbp, flags)
298 	const DB *dbp;
299 	u_int32_t flags;
300 {
301 	if (flags != 0)
302 		return (__db_ferr(dbp->dbenv, "DB->join", 0));
303 
304 	return (0);
305 }
306 
307 /*
308  * __db_putchk --
309  *	Common put argument checking routine.
310  *
311  * PUBLIC: int __db_putchk
312  * PUBLIC:    __P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
313  */
314 int
__db_putchk(dbp,key,data,flags,isrdonly,isdup)315 __db_putchk(dbp, key, data, flags, isrdonly, isdup)
316 	const DB *dbp;
317 	DBT *key;
318 	const DBT *data;
319 	u_int32_t flags;
320 	int isrdonly, isdup;
321 {
322 	int ret;
323 
324 	/* Check for changes to a read-only tree. */
325 	if (isrdonly)
326 		return (__db_rdonly(dbp->dbenv, "put"));
327 
328 	/* Check for invalid function flags. */
329 	switch (flags) {
330 	case 0:
331 	case DB_NOOVERWRITE:
332 		break;
333 	case DB_APPEND:
334 		if (dbp->type != DB_RECNO)
335 			goto err;
336 		break;
337 	default:
338 err:		return (__db_ferr(dbp->dbenv, "DB->put", 0));
339 	}
340 
341 	/* Check for invalid key/data flags. */
342 	if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
343 		return (ret);
344 	if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
345 		return (ret);
346 
347 	/* Check for missing keys. */
348 	if (key->data == NULL || key->size == 0)
349 		return (__db_keyempty(dbp->dbenv));
350 
351 	/* Check for partial puts in the presence of duplicates. */
352 	if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) {
353 		__db_err(dbp->dbenv,
354 "a partial put in the presence of duplicates requires a cursor operation");
355 		return (EINVAL);
356 	}
357 
358 	return (0);
359 }
360 
361 /*
362  * __db_statchk --
363  *	Common stat argument checking routine.
364  *
365  * PUBLIC: int __db_statchk __P((const DB *, u_int32_t));
366  */
367 int
__db_statchk(dbp,flags)368 __db_statchk(dbp, flags)
369 	const DB *dbp;
370 	u_int32_t flags;
371 {
372 	/* Check for invalid function flags. */
373 	switch (flags) {
374 	case 0:
375 		break;
376 	case DB_RECORDCOUNT:
377 		if (dbp->type == DB_RECNO)
378 			break;
379 		if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_BT_RECNUM))
380 			break;
381 		goto err;
382 	default:
383 err:		return (__db_ferr(dbp->dbenv, "DB->stat", 0));
384 	}
385 
386 	return (0);
387 }
388 
389 /*
390  * __db_syncchk --
391  *	Common sync argument checking routine.
392  *
393  * PUBLIC: int __db_syncchk __P((const DB *, u_int32_t));
394  */
395 int
__db_syncchk(dbp,flags)396 __db_syncchk(dbp, flags)
397 	const DB *dbp;
398 	u_int32_t flags;
399 {
400 	/* Check for invalid function flags. */
401 	switch (flags) {
402 	case 0:
403 		break;
404 	default:
405 		return (__db_ferr(dbp->dbenv, "DB->sync", 0));
406 	}
407 
408 	return (0);
409 }
410 
411 /*
412  * __dbt_ferr --
413  *	Check a DBT for flag errors.
414  */
415 static int
__dbt_ferr(dbp,name,dbt,check_thread)416 __dbt_ferr(dbp, name, dbt, check_thread)
417 	const DB *dbp;
418 	const char *name;
419 	const DBT *dbt;
420 	int check_thread;
421 {
422 	int ret;
423 
424 	/*
425 	 * Check for invalid DBT flags.  We allow any of the flags to be
426 	 * specified to any DB or DBcursor call so that applications can
427 	 * set DB_DBT_MALLOC when retrieving a data item from a secondary
428 	 * database and then specify that same DBT as a key to a primary
429 	 * database, without having to clear flags.
430 	 */
431 	if ((ret = __db_fchk(dbp->dbenv, name, dbt->flags,
432 	    DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0)
433 		return (ret);
434 	if ((ret = __db_fcchk(dbp->dbenv, name,
435 	    dbt->flags, DB_DBT_MALLOC, DB_DBT_USERMEM)) != 0)
436 		return (ret);
437 
438 	if (check_thread && F_ISSET(dbp, DB_AM_THREAD) &&
439 	    !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_USERMEM)) {
440 		__db_err(dbp->dbenv,
441 		    "missing flag thread flag for %s DBT", name);
442 		return (EINVAL);
443 	}
444 	return (0);
445 }
446 
447 /*
448  * __db_eopnotsup --
449  *	Common operation not supported message.
450  *
451  * PUBLIC: int __db_eopnotsup __P((const DB_ENV *));
452  */
453 int
__db_eopnotsup(dbenv)454 __db_eopnotsup(dbenv)
455 	const DB_ENV *dbenv;
456 {
457 	__db_err(dbenv, "operation not supported");
458 #ifdef EOPNOTSUPP
459 	return (EOPNOTSUPP);
460 #else
461 	return (EINVAL);
462 #endif
463 }
464 
465 /*
466  * __db_keyempty --
467  *	Common missing or empty key value message.
468  */
469 static int
__db_keyempty(dbenv)470 __db_keyempty(dbenv)
471 	const DB_ENV *dbenv;
472 {
473 	__db_err(dbenv, "missing or empty key value specified");
474 	return (EINVAL);
475 }
476 
477 /*
478  * __db_rdonly --
479  *	Common readonly message.
480  */
481 static int
__db_rdonly(dbenv,name)482 __db_rdonly(dbenv, name)
483 	const DB_ENV *dbenv;
484 	const char *name;
485 {
486 	__db_err(dbenv, "%s: attempt to modify a read-only tree", name);
487 	return (EACCES);
488 }
489