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