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