1 /* $OpenBSD: ndbm.c,v 1.22 2007/09/17 07:07:23 moritz Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Margo Seltzer. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <string.h> 41 42 #include <ndbm.h> 43 #include <dbm.h> 44 #include "hash.h" 45 46 /* 47 * 48 * This package provides dbm and ndbm compatible interfaces to DB. 49 * First are the DBM routines, which call the NDBM routines, and 50 * the NDBM routines, which call the DB routines. 51 */ 52 static DBM *__cur_db; 53 54 static DBM *_dbm_open(const char *, const char *, int, mode_t); 55 56 /* 57 * Returns: 58 * 0 on success 59 * <0 on failure 60 */ 61 int 62 dbminit(file) 63 const char *file; 64 { 65 66 if (__cur_db != NULL) 67 (void)dbm_close(__cur_db); 68 if ((__cur_db = _dbm_open(file, ".pag", O_RDWR, 0)) != NULL) 69 return (0); 70 if ((__cur_db = _dbm_open(file, ".pag", O_RDONLY, 0)) != NULL) 71 return (0); 72 return (-1); 73 } 74 75 /* 76 * Returns: 77 * 0 on success 78 * <0 on failure 79 */ 80 int 81 dbmclose() 82 { 83 int rval; 84 85 if (__cur_db == NULL) 86 return (-1); 87 rval = (__cur_db->close)(__cur_db); 88 __cur_db = NULL; 89 return (rval); 90 } 91 92 /* 93 * Returns: 94 * DATUM on success 95 * NULL on failure 96 */ 97 datum 98 fetch(key) 99 datum key; 100 { 101 datum item; 102 103 if (__cur_db == NULL) { 104 item.dptr = NULL; 105 item.dsize = 0; 106 return (item); 107 } 108 return (dbm_fetch(__cur_db, key)); 109 } 110 111 /* 112 * Returns: 113 * DATUM on success 114 * NULL on failure 115 */ 116 datum 117 firstkey() 118 { 119 datum item; 120 121 if (__cur_db == NULL) { 122 item.dptr = NULL; 123 item.dsize = 0; 124 return (item); 125 } 126 return (dbm_firstkey(__cur_db)); 127 } 128 129 /* 130 * Returns: 131 * DATUM on success 132 * NULL on failure 133 */ 134 /* ARGSUSED */ 135 datum 136 nextkey(datum key) 137 { 138 datum item; 139 140 if (__cur_db == NULL) { 141 item.dptr = NULL; 142 item.dsize = 0; 143 return (item); 144 } 145 return (dbm_nextkey(__cur_db)); 146 } 147 148 /* 149 * Returns: 150 * 0 on success 151 * <0 on failure 152 */ 153 int 154 delete(key) 155 datum key; 156 { 157 158 if (__cur_db == NULL || dbm_rdonly(__cur_db)) 159 return (-1); 160 return (dbm_delete(__cur_db, key)); 161 } 162 163 /* 164 * Returns: 165 * 0 on success 166 * <0 on failure 167 */ 168 int 169 store(key, dat) 170 datum key, dat; 171 { 172 173 if (__cur_db == NULL || dbm_rdonly(__cur_db)) 174 return (-1); 175 return (dbm_store(__cur_db, key, dat, DBM_REPLACE)); 176 } 177 178 /* 179 * Returns: 180 * *DBM on success 181 * NULL on failure 182 */ 183 static DBM * 184 _dbm_open(file, suff, flags, mode) 185 const char *file; 186 const char *suff; 187 int flags; 188 mode_t mode; 189 { 190 HASHINFO info; 191 char path[MAXPATHLEN]; 192 int len; 193 194 len = snprintf(path, sizeof path, "%s%s", file, suff); 195 if (len < 0 || len >= sizeof path) { 196 errno = ENAMETOOLONG; 197 return (NULL); 198 } 199 /* O_WRONLY not supported by db(3) but traditional ndbm allowed it. */ 200 if ((flags & O_ACCMODE) == O_WRONLY) { 201 flags &= ~O_WRONLY; 202 flags |= O_RDWR; 203 } 204 info.bsize = 4096; 205 info.ffactor = 40; 206 info.nelem = 1; 207 info.cachesize = 0; 208 info.hash = NULL; 209 info.lorder = 0; 210 return ((DBM *)__hash_open(path, flags, mode, &info, 0)); 211 } 212 213 /* 214 * Returns: 215 * *DBM on success 216 * NULL on failure 217 */ 218 DBM * 219 dbm_open(file, flags, mode) 220 const char *file; 221 int flags; 222 mode_t mode; 223 { 224 225 return(_dbm_open(file, DBM_SUFFIX, flags, mode)); 226 } 227 228 /* 229 * Returns: 230 * Nothing. 231 */ 232 void 233 dbm_close(db) 234 DBM *db; 235 { 236 237 (void)(db->close)(db); 238 } 239 240 /* 241 * Returns: 242 * DATUM on success 243 * NULL on failure 244 */ 245 datum 246 dbm_fetch(db, key) 247 DBM *db; 248 datum key; 249 { 250 datum retdata; 251 int status; 252 DBT dbtkey, dbtretdata; 253 254 dbtkey.data = key.dptr; 255 dbtkey.size = key.dsize; 256 status = (db->get)(db, &dbtkey, &dbtretdata, 0); 257 if (status) { 258 dbtretdata.data = NULL; 259 dbtretdata.size = 0; 260 } 261 retdata.dptr = dbtretdata.data; 262 retdata.dsize = dbtretdata.size; 263 return (retdata); 264 } 265 266 /* 267 * Returns: 268 * DATUM on success 269 * NULL on failure 270 */ 271 datum 272 dbm_firstkey(db) 273 DBM *db; 274 { 275 int status; 276 datum retkey; 277 DBT dbtretkey, dbtretdata; 278 279 status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST); 280 if (status) 281 dbtretkey.data = NULL; 282 retkey.dptr = dbtretkey.data; 283 retkey.dsize = dbtretkey.size; 284 return (retkey); 285 } 286 287 /* 288 * Returns: 289 * DATUM on success 290 * NULL on failure 291 */ 292 datum 293 dbm_nextkey(db) 294 DBM *db; 295 { 296 int status; 297 datum retkey; 298 DBT dbtretkey, dbtretdata; 299 300 status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT); 301 if (status) 302 dbtretkey.data = NULL; 303 retkey.dptr = dbtretkey.data; 304 retkey.dsize = dbtretkey.size; 305 return (retkey); 306 } 307 308 /* 309 * Returns: 310 * 0 on success 311 * <0 on failure 312 */ 313 int 314 dbm_delete(db, key) 315 DBM *db; 316 datum key; 317 { 318 int status; 319 DBT dbtkey; 320 321 dbtkey.data = key.dptr; 322 dbtkey.size = key.dsize; 323 status = (db->del)(db, &dbtkey, 0); 324 if (status) 325 return (-1); 326 else 327 return (0); 328 } 329 330 /* 331 * Returns: 332 * 0 on success 333 * <0 on failure 334 * 1 if DBM_INSERT and entry exists 335 */ 336 int 337 dbm_store(db, key, data, flags) 338 DBM *db; 339 datum key, data; 340 int flags; 341 { 342 DBT dbtkey, dbtdata; 343 344 dbtkey.data = key.dptr; 345 dbtkey.size = key.dsize; 346 dbtdata.data = data.dptr; 347 dbtdata.size = data.dsize; 348 return ((db->put)(db, &dbtkey, &dbtdata, 349 (flags == DBM_INSERT) ? R_NOOVERWRITE : 0)); 350 } 351 352 int 353 dbm_error(db) 354 DBM *db; 355 { 356 HTAB *hp; 357 358 hp = (HTAB *)db->internal; 359 return (hp->err); 360 } 361 362 int 363 dbm_clearerr(db) 364 DBM *db; 365 { 366 HTAB *hp; 367 368 hp = (HTAB *)db->internal; 369 hp->err = 0; 370 return (0); 371 } 372 373 int 374 dbm_dirfno(db) 375 DBM *db; 376 { 377 378 return(((HTAB *)db->internal)->fp); 379 } 380 381 int 382 dbm_rdonly(dbp) 383 DBM *dbp; 384 { 385 HTAB *hashp = (HTAB *)dbp->internal; 386 387 /* Could use DBM_RDONLY instead if we wanted... */ 388 return ((hashp->flags & O_ACCMODE) == O_RDONLY); 389 } 390