Merge from vendor branch LIBSTDC++:
[dragonfly.git] / contrib / sendmail / libsmdb / smdb1.c
1 /*
2 ** Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 **      All rights reserved.
4 **
5 ** By using this file, you agree to the terms and conditions set
6 ** forth in the LICENSE file which can be found at the top level of
7 ** the sendmail distribution.
8 */
9
10 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: smdb1.c,v 8.58 2002/05/24 23:09:11 gshapiro Exp $")
12
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16
17 #include <sendmail/sendmail.h>
18 #include <libsmdb/smdb.h>
19
20 #if (DB_VERSION_MAJOR == 1)
21
22 # define SMDB1_FILE_EXTENSION "db"
23
24 struct smdb_db1_struct
25 {
26         DB      *smdb1_db;
27         int     smdb1_lock_fd;
28         bool    smdb1_cursor_in_use;
29 };
30 typedef struct smdb_db1_struct SMDB_DB1_DATABASE;
31
32 struct smdb_db1_cursor
33 {
34         SMDB_DB1_DATABASE       *db;
35 };
36 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
37
38 /*
39 **  SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type.
40 **
41 **      Parameters:
42 **              type -- The type to translate.
43 **
44 **      Returns:
45 **              The DB1 type that corresponsds to the passed in SMDB type.
46 **              Returns -1 if there is no equivalent type.
47 **
48 */
49
50 DBTYPE
51 smdb_type_to_db1_type(type)
52         SMDB_DBTYPE type;
53 {
54         if (type == SMDB_TYPE_DEFAULT)
55                 return DB_HASH;
56
57         if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
58                 return DB_HASH;
59
60         if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
61                 return DB_BTREE;
62
63         /* Should never get here thanks to test in smdb_db_open() */
64         return DB_HASH;
65 }
66 /*
67 **  SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags.
68 **
69 **      Parameters:
70 **              flags -- The flags to translate.
71 **
72 **      Returns:
73 **              The db1 flags that are equivalent to the smdb flags.
74 **
75 **      Notes:
76 **              Any invalid flags are ignored.
77 **
78 */
79
80 unsigned int
81 smdb_put_flags_to_db1_flags(flags)
82         SMDB_FLAG flags;
83 {
84         int return_flags;
85
86         return_flags = 0;
87
88         if (bitset(SMDBF_NO_OVERWRITE, flags))
89                 return_flags |= R_NOOVERWRITE;
90
91         return return_flags;
92 }
93 /*
94 **  SMDB_CURSOR_GET_FLAGS_TO_SMDB1
95 **
96 **      Parameters:
97 **              flags -- The flags to translate.
98 **
99 **      Returns:
100 **              The db1 flags that are equivalent to the smdb flags.
101 **
102 **      Notes:
103 **              Returns -1 if we don't support the flag.
104 **
105 */
106
107 int
108 smdb_cursor_get_flags_to_smdb1(flags)
109         SMDB_FLAG flags;
110 {
111         switch(flags)
112         {
113                 case SMDB_CURSOR_GET_FIRST:
114                         return R_FIRST;
115
116                 case SMDB_CURSOR_GET_LAST:
117                         return R_LAST;
118
119                 case SMDB_CURSOR_GET_NEXT:
120                         return R_NEXT;
121
122                 case SMDB_CURSOR_GET_RANGE:
123                         return R_CURSOR;
124
125                 default:
126                         return -1;
127         }
128 }
129
130 /*
131 **  The rest of these functions correspond to the interface laid out in smdb.h.
132 */
133
134 SMDB_DB1_DATABASE *
135 smdb1_malloc_database()
136 {
137         SMDB_DB1_DATABASE *db1;
138
139         db1 = (SMDB_DB1_DATABASE *) malloc(sizeof(SMDB_DB1_DATABASE));
140
141         if (db1 != NULL)
142         {
143                 db1->smdb1_lock_fd = -1;
144                 db1->smdb1_cursor_in_use = false;
145         }
146
147         return db1;
148 }
149
150 int
151 smdb1_close(database)
152         SMDB_DATABASE *database;
153 {
154         int result;
155         SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
156         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
157
158         result = db->close(db);
159         if (db1->smdb1_lock_fd != -1)
160                 (void) close(db1->smdb1_lock_fd);
161
162         free(db1);
163         database->smdb_impl = NULL;
164
165         return result;
166 }
167
168 int
169 smdb1_del(database, key, flags)
170         SMDB_DATABASE *database;
171         SMDB_DBENT *key;
172         unsigned int flags;
173 {
174         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
175         DBT dbkey;
176
177         (void) memset(&dbkey, '\0', sizeof dbkey);
178         dbkey.data = key->data;
179         dbkey.size = key->size;
180         return db->del(db, &dbkey, flags);
181 }
182
183 int
184 smdb1_fd(database, fd)
185         SMDB_DATABASE *database;
186         int *fd;
187 {
188         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
189
190         *fd = db->fd(db);
191         if (*fd == -1)
192                 return errno;
193
194         return SMDBE_OK;
195 }
196
197 int
198 smdb1_lockfd(database)
199         SMDB_DATABASE *database;
200 {
201         SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
202
203         return db1->smdb1_lock_fd;
204 }
205
206
207 int
208 smdb1_get(database, key, data, flags)
209         SMDB_DATABASE *database;
210         SMDB_DBENT *key;
211         SMDB_DBENT *data;
212         unsigned int flags;
213 {
214         int result;
215         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
216         DBT dbkey, dbdata;
217
218         (void) memset(&dbdata, '\0', sizeof dbdata);
219         (void) memset(&dbkey, '\0', sizeof dbkey);
220         dbkey.data = key->data;
221         dbkey.size = key->size;
222
223         result = db->get(db, &dbkey, &dbdata, flags);
224         if (result != 0)
225         {
226                 if (result == 1)
227                         return SMDBE_NOT_FOUND;
228                 return errno;
229         }
230         data->data = dbdata.data;
231         data->size = dbdata.size;
232         return SMDBE_OK;
233 }
234
235 int
236 smdb1_put(database, key, data, flags)
237         SMDB_DATABASE *database;
238         SMDB_DBENT *key;
239         SMDB_DBENT *data;
240         unsigned int flags;
241 {
242         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
243         DBT dbkey, dbdata;
244
245         (void) memset(&dbdata, '\0', sizeof dbdata);
246         (void) memset(&dbkey, '\0', sizeof dbkey);
247         dbkey.data = key->data;
248         dbkey.size = key->size;
249         dbdata.data = data->data;
250         dbdata.size = data->size;
251
252         return db->put(db, &dbkey, &dbdata,
253                        smdb_put_flags_to_db1_flags(flags));
254 }
255
256 int
257 smdb1_set_owner(database, uid, gid)
258         SMDB_DATABASE *database;
259         uid_t uid;
260         gid_t gid;
261 {
262 # if HASFCHOWN
263         int fd;
264         int result;
265         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
266
267         fd = db->fd(db);
268         if (fd == -1)
269                 return errno;
270
271         result = fchown(fd, uid, gid);
272         if (result < 0)
273                 return errno;
274 # endif /* HASFCHOWN */
275
276         return SMDBE_OK;
277 }
278
279 int
280 smdb1_sync(database, flags)
281         SMDB_DATABASE *database;
282         unsigned int flags;
283 {
284         DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
285
286         return db->sync(db, flags);
287 }
288
289 int
290 smdb1_cursor_close(cursor)
291         SMDB_CURSOR *cursor;
292 {
293         SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
294         SMDB_DB1_DATABASE *db1 = db1_cursor->db;
295
296         if (!db1->smdb1_cursor_in_use)
297                 return SMDBE_NOT_A_VALID_CURSOR;
298
299         db1->smdb1_cursor_in_use = false;
300         free(cursor);
301
302         return SMDBE_OK;
303 }
304
305 int
306 smdb1_cursor_del(cursor, flags)
307         SMDB_CURSOR *cursor;
308         unsigned int flags;
309 {
310         SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
311         SMDB_DB1_DATABASE *db1 = db1_cursor->db;
312         DB *db = db1->smdb1_db;
313
314         return db->del(db, NULL, R_CURSOR);
315 }
316
317 int
318 smdb1_cursor_get(cursor, key, value, flags)
319         SMDB_CURSOR *cursor;
320         SMDB_DBENT *key;
321         SMDB_DBENT *value;
322         SMDB_FLAG flags;
323 {
324         int db1_flags;
325         int result;
326         SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
327         SMDB_DB1_DATABASE *db1 = db1_cursor->db;
328         DB *db = db1->smdb1_db;
329         DBT dbkey, dbdata;
330
331         (void) memset(&dbdata, '\0', sizeof dbdata);
332         (void) memset(&dbkey, '\0', sizeof dbkey);
333
334         db1_flags = smdb_cursor_get_flags_to_smdb1(flags);
335         result = db->seq(db, &dbkey, &dbdata, db1_flags);
336         if (result == -1)
337                 return errno;
338         if (result == 1)
339                 return SMDBE_LAST_ENTRY;
340         value->data = dbdata.data;
341         value->size = dbdata.size;
342         key->data = dbkey.data;
343         key->size = dbkey.size;
344         return SMDBE_OK;
345 }
346
347 int
348 smdb1_cursor_put(cursor, key, value, flags)
349         SMDB_CURSOR *cursor;
350         SMDB_DBENT *key;
351         SMDB_DBENT *value;
352         SMDB_FLAG flags;
353 {
354         SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
355         SMDB_DB1_DATABASE *db1 = db1_cursor->db;
356         DB *db = db1->smdb1_db;
357         DBT dbkey, dbdata;
358
359         (void) memset(&dbdata, '\0', sizeof dbdata);
360         (void) memset(&dbkey, '\0', sizeof dbkey);
361         dbkey.data = key->data;
362         dbkey.size = key->size;
363         dbdata.data = value->data;
364         dbdata.size = value->size;
365
366         return db->put(db, &dbkey, &dbdata, R_CURSOR);
367 }
368
369 int
370 smdb1_cursor(database, cursor, flags)
371         SMDB_DATABASE *database;
372         SMDB_CURSOR **cursor;
373         unsigned int flags;
374 {
375         SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
376         SMDB_CURSOR *cur;
377         SMDB_DB1_CURSOR *db1_cursor;
378
379         if (db1->smdb1_cursor_in_use)
380                 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
381
382         db1->smdb1_cursor_in_use = true;
383         db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR));
384         db1_cursor->db = db1;
385
386         cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
387
388         if (cur == NULL)
389                 return SMDBE_MALLOC;
390
391         cur->smdbc_impl = db1_cursor;
392         cur->smdbc_close = smdb1_cursor_close;
393         cur->smdbc_del = smdb1_cursor_del;
394         cur->smdbc_get = smdb1_cursor_get;
395         cur->smdbc_put = smdb1_cursor_put;
396         *cursor = cur;
397
398         return SMDBE_OK;
399 }
400 /*
401 **  SMDB_DB_OPEN -- Opens a db1 database.
402 **
403 **      Parameters:
404 **              database -- An unallocated database pointer to a pointer.
405 **              db_name -- The name of the database without extension.
406 **              mode -- File permisions on the database if created.
407 **              mode_mask -- Mode bits that must match on an existing database.
408 **              sff -- Flags for safefile.
409 **              type -- The type of database to open
410 **                      See smdb_type_to_db1_type for valid types.
411 **              user_info -- Information on the user to use for file
412 **                          permissions.
413 **              db_params --
414 **                      An SMDB_DBPARAMS struct including params. These
415 **                      are processed according to the type of the
416 **                      database. Currently supported params (only for
417 **                      HASH type) are:
418 **                         num_elements
419 **                         cache_size
420 **
421 **      Returns:
422 **              SMDBE_OK -- Success, otherwise errno.
423 */
424
425 int
426 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
427              db_params)
428         SMDB_DATABASE **database;
429         char *db_name;
430         int mode;
431         int mode_mask;
432         long sff;
433         SMDB_DBTYPE type;
434         SMDB_USER_INFO *user_info;
435         SMDB_DBPARAMS *db_params;
436 {
437         bool lockcreated = false;
438         int db_fd;
439         int lock_fd;
440         int result;
441         void *params;
442         SMDB_DATABASE *smdb_db;
443         SMDB_DB1_DATABASE *db1;
444         DB *db;
445         HASHINFO hash_info;
446         BTREEINFO btree_info;
447         DBTYPE db_type;
448         struct stat stat_info;
449         char db_file_name[MAXPATHLEN];
450
451         if (type == NULL ||
452             (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) != 0 &&
453              strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) != 0))
454                 return SMDBE_UNKNOWN_DB_TYPE;
455
456         result = smdb_add_extension(db_file_name, sizeof db_file_name,
457                                     db_name, SMDB1_FILE_EXTENSION);
458         if (result != SMDBE_OK)
459                 return result;
460
461         result = smdb_setup_file(db_name, SMDB1_FILE_EXTENSION, mode_mask,
462                                  sff, user_info, &stat_info);
463         if (result != SMDBE_OK)
464                 return result;
465
466         if (stat_info.st_mode == ST_MODE_NOFILE &&
467             bitset(mode, O_CREAT))
468                 lockcreated = true;
469
470         lock_fd = -1;
471         result = smdb_lock_file(&lock_fd, db_name, mode, sff,
472                                 SMDB1_FILE_EXTENSION);
473         if (result != SMDBE_OK)
474                 return result;
475
476         if (lockcreated)
477         {
478                 mode |= O_TRUNC;
479                 mode &= ~(O_CREAT|O_EXCL);
480         }
481
482         *database = NULL;
483
484         smdb_db = smdb_malloc_database();
485         db1 = smdb1_malloc_database();
486         if (smdb_db == NULL || db1 == NULL)
487                 return SMDBE_MALLOC;
488         db1->smdb1_lock_fd = lock_fd;
489
490         params = NULL;
491         if (db_params != NULL &&
492             (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0))
493         {
494                 (void) memset(&hash_info, '\0', sizeof hash_info);
495                 hash_info.nelem = db_params->smdbp_num_elements;
496                 hash_info.cachesize = db_params->smdbp_cache_size;
497                 params = &hash_info;
498         }
499
500         if (db_params != NULL &&
501             (strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0))
502         {
503                 (void) memset(&btree_info, '\0', sizeof btree_info);
504                 btree_info.cachesize = db_params->smdbp_cache_size;
505                 if (db_params->smdbp_allow_dup)
506                         btree_info.flags |= R_DUP;
507                 params = &btree_info;
508         }
509
510         db_type = smdb_type_to_db1_type(type);
511         db = dbopen(db_file_name, mode, DBMMODE, db_type, params);
512         if (db != NULL)
513         {
514                 db_fd = db->fd(db);
515                 result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd,
516                                           &stat_info);
517         }
518         else
519         {
520                 if (errno == 0)
521                         result = SMDBE_BAD_OPEN;
522                 else
523                         result = errno;
524         }
525
526         if (result == SMDBE_OK)
527         {
528                 /* Everything is ok. Setup driver */
529                 db1->smdb1_db = db;
530
531                 smdb_db->smdb_close = smdb1_close;
532                 smdb_db->smdb_del = smdb1_del;
533                 smdb_db->smdb_fd = smdb1_fd;
534                 smdb_db->smdb_lockfd = smdb1_lockfd;
535                 smdb_db->smdb_get = smdb1_get;
536                 smdb_db->smdb_put = smdb1_put;
537                 smdb_db->smdb_set_owner = smdb1_set_owner;
538                 smdb_db->smdb_sync = smdb1_sync;
539                 smdb_db->smdb_cursor = smdb1_cursor;
540                 smdb_db->smdb_impl = db1;
541
542                 *database = smdb_db;
543                 return SMDBE_OK;
544         }
545
546         if (db != NULL)
547                 (void) db->close(db);
548
549         /* Error opening database */
550         (void) smdb_unlock_file(db1->smdb1_lock_fd);
551         free(db1);
552         smdb_free_database(smdb_db);
553
554         return result;
555 }
556
557 #endif /* (DB_VERSION_MAJOR == 1) */