Annotation of parser3/src/lib/sdbm/sdbm.c, revision 1.4

1.1       paf         1: /* ====================================================================
                      2:  * The Apache Software License, Version 1.1
                      3:  *
                      4:  * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
                      5:  * reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  *
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  *
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in
                     16:  *    the documentation and/or other materials provided with the
                     17:  *    distribution.
                     18:  *
                     19:  * 3. The end-user documentation included with the redistribution,
                     20:  *    if any, must include the following acknowledgment:
                     21:  *       "This product includes software developed by the
                     22:  *        Apache Software Foundation (http://www.apache.org/)."
                     23:  *    Alternately, this acknowledgment may appear in the software itself,
                     24:  *    if and wherever such third-party acknowledgments normally appear.
                     25:  *
                     26:  * 4. The names "Apache" and "Apache Software Foundation" must
                     27:  *    not be used to endorse or promote products derived from this
                     28:  *    software without prior written permission. For written
                     29:  *    permission, please contact apache@apache.org.
                     30:  *
                     31:  * 5. Products derived from this software may not be called "Apache",
                     32:  *    nor may "Apache" appear in their name, without prior written
                     33:  *    permission of the Apache Software Foundation.
                     34:  *
                     35:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
                     36:  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     37:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     38:  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
                     39:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     40:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     41:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
                     42:  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
                     43:  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     44:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
                     45:  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     46:  * SUCH DAMAGE.
                     47:  * ====================================================================
                     48:  *
                     49:  * This software consists of voluntary contributions made by many
                     50:  * individuals on behalf of the Apache Software Foundation.  For more
                     51:  * information on the Apache Software Foundation, please see
                     52:  * <http://www.apache.org/>.
                     53:  */
                     54: 
                     55: /*
                     56:  * sdbm - ndbm work-alike hashed database library
                     57:  * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
                     58:  * author: oz@nexus.yorku.ca
                     59:  * ex-public domain, ported to APR for Apache 2
                     60:  * core routines
                     61:  */
                     62: 
                     63: #include "apr.h"
                     64: #include "apr_file_io.h"
                     65: #include "apr_strings.h"
                     66: #include "apr_errno.h"
                     67: #include "apr_sdbm.h"
                     68: 
                     69: #include "sdbm_tune.h"
                     70: #include "sdbm_pair.h"
                     71: #include "sdbm_private.h"
                     72: 
                     73: #include <string.h>     /* for memset() */
1.4     ! misha      74: // #include <stdlib.h>     /* for malloc() and free() */
1.1       paf        75: 
                     76: /*
                     77:  * forward
                     78:  */
                     79: static int getdbit (apr_sdbm_t *, long);
                     80: static apr_status_t setdbit(apr_sdbm_t *, long);
                     81: static apr_status_t getpage(apr_sdbm_t *db, long);
                     82: static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db);
                     83: static apr_status_t makroom(apr_sdbm_t *, long, int);
                     84: 
                     85: /*
                     86:  * useful macros
                     87:  */
                     88: #define bad(x)         ((x).dptr == NULL || (x).dsize <= 0)
                     89: #define exhash(item)   sdbm_hash((item).dptr, (item).dsize)
                     90: 
                     91: /* ### Does anything need these externally? */
                     92: #define sdbm_dirfno(db)        ((db)->dirf)
                     93: #define sdbm_pagfno(db)        ((db)->pagf)
                     94: 
                     95: #define OFF_PAG(off)   (apr_off_t) (off) * PBLKSIZ
                     96: #define OFF_DIR(off)   (apr_off_t) (off) * DBLKSIZ
                     97: 
                     98: static long masks[] = {
                     99:         000000000000, 000000000001, 000000000003, 000000000007,
                    100:         000000000017, 000000000037, 000000000077, 000000000177,
                    101:         000000000377, 000000000777, 000000001777, 000000003777,
                    102:         000000007777, 000000017777, 000000037777, 000000077777,
                    103:         000000177777, 000000377777, 000000777777, 000001777777,
                    104:         000003777777, 000007777777, 000017777777, 000037777777,
                    105:         000077777777, 000177777777, 000377777777, 000777777777,
                    106:         001777777777, 003777777777, 007777777777, 017777777777
                    107: };
                    108: 
                    109: const apr_sdbm_datum_t sdbm_nullitem = { NULL, 0 };
                    110: 
                    111: static apr_status_t database_cleanup(void *data)
                    112: {
                    113:     apr_sdbm_t *db = data;
                    114: 
                    115:     /*
                    116:      * Can't rely on apr_sdbm_unlock, since it will merely
                    117:      * decrement the refcnt if several locks are held.
                    118:      */
                    119:     if (db->flags & (SDBM_SHARED_LOCK | SDBM_EXCLUSIVE_LOCK))
                    120:         (void) apr_file_unlock(db->dirf);
                    121:     (void) apr_file_close(db->dirf);
                    122:     (void) apr_file_close(db->pagf);
1.4     ! misha     123: //    free(db); // libcg will do it
1.1       paf       124: 
                    125:     return APR_SUCCESS;
                    126: }
                    127: 
                    128: static apr_status_t prep(apr_sdbm_t **pdb, const char *dirname, const char *pagname,
                    129:                          apr_int32_t flags, apr_fileperms_t perms, apr_pool_t *p)
                    130: {
                    131:     apr_sdbm_t *db;
                    132:     apr_status_t status;
                    133: 
                    134:     *pdb = NULL;
                    135: 
1.4     ! misha     136: //    db = malloc(sizeof(*db));
        !           137: //    memset(db, 0, sizeof(*db));
        !           138:        db = apr_malloc(sizeof(*db));
1.1       paf       139: 
                    140:     db->pool = p;
                    141: 
                    142:     /*
                    143:      * adjust user flags so that WRONLY becomes RDWR, 
                    144:      * as required by this package. Also set our internal
                    145:      * flag for RDONLY if needed.
                    146:      */
                    147:     if (!(flags & APR_WRITE)) {
                    148:         db->flags |= SDBM_RDONLY;
                    149:     }
                    150: 
                    151:     /*
                    152:      * adjust the file open flags so that we handle locking
                    153:      * on our own (don't rely on any locking behavior within
                    154:      * an apr_file_t, in case it's ever introduced, and set
                    155:      * our own flag.
                    156:      */
                    157:     if (flags & APR_SHARELOCK) {
                    158:         db->flags |= SDBM_SHARED;
                    159:         flags &= ~APR_SHARELOCK;
                    160:     }
                    161: 
                    162:     flags |= APR_BINARY | APR_READ;
                    163: 
                    164:     /*
                    165:      * open the files in sequence, and stat the dirfile.
                    166:      * If we fail anywhere, undo everything, return NULL.
                    167:      */
                    168: 
                    169:     if ((status = apr_file_open(&db->dirf, dirname, flags, perms, p))
                    170:                 != APR_SUCCESS)
                    171:         goto error;
                    172: 
                    173:     if ((status = apr_file_open(&db->pagf, pagname, flags, perms, p))
                    174:                 != APR_SUCCESS)
                    175:         goto error;
                    176: 
                    177:     if ((status = apr_sdbm_lock(db, (db->flags & SDBM_RDONLY) 
                    178:                                         ? APR_FLOCK_SHARED
                    179:                                         : APR_FLOCK_EXCLUSIVE))
                    180:                 != APR_SUCCESS)
                    181:         goto error;
                    182: 
                    183:     /* apr_pcalloc zeroed the buffers
                    184:      * apr_sdbm_lock stated the dirf->size and invalidated the cache
                    185:      */
                    186: 
                    187:     /*
                    188:      * if we are opened in SHARED mode, unlock ourself 
                    189:      */
                    190:     if (db->flags & SDBM_SHARED)
                    191:         if ((status = apr_sdbm_unlock(db)) != APR_SUCCESS)
                    192:             goto error;
                    193: 
                    194:     /* make sure that we close the database at some point */
1.2       paf       195:     //apr_pool_cleanup_register(p, db, database_cleanup, apr_pool_cleanup_null);
1.1       paf       196: 
                    197:     /* Done! */
                    198:     *pdb = db;
                    199:     return APR_SUCCESS;
                    200: 
                    201: error:
                    202:     if (db->dirf && db->pagf)
                    203:         (void) apr_sdbm_unlock(db);
                    204:     if (db->dirf != NULL)
                    205:         (void) apr_file_close(db->dirf);
                    206:     if (db->pagf != NULL) {
                    207:         (void) apr_file_close(db->pagf);
                    208:     }
1.4     ! misha     209: //    free(db); // libcg will do it
1.1       paf       210:     return status;
                    211: }
                    212: 
                    213: APU_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *file, 
                    214:                                         apr_int32_t flags, 
                    215:                                         apr_fileperms_t perms, apr_pool_t *p)
                    216: {
                    217:     char *dirname = apr_pstrcat(p, file, APR_SDBM_DIRFEXT, NULL);
                    218:     char *pagname = apr_pstrcat(p, file, APR_SDBM_PAGFEXT, NULL);
                    219:     
                    220:     return prep(db, dirname, pagname, flags, perms, p);
                    221: }
                    222: 
                    223: APU_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db)
                    224: {
1.2       paf       225:        database_cleanup(db); return APR_SUCCESS;
                    226:     //return apr_pool_cleanup_run(db->pool, db, database_cleanup);
1.1       paf       227: }
                    228: 
                    229: APU_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, apr_sdbm_datum_t *val,
                    230:                                          apr_sdbm_datum_t key)
                    231: {
                    232:     apr_status_t status;
                    233:     
                    234:     if (db == NULL || bad(key))
                    235:         return APR_EINVAL;
                    236: 
                    237:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
                    238:         return status;
                    239: 
                    240:     if ((status = getpage(db, exhash(key))) == APR_SUCCESS) {
                    241:         *val = getpair(db->pagbuf, key);
                    242:         /* ### do we want a not-found result? */
                    243:     }
                    244: 
                    245:     (void) apr_sdbm_unlock(db);
                    246: 
                    247:     return status;
                    248: }
                    249: 
                    250: static apr_status_t write_page(apr_sdbm_t *db, const char *buf, long pagno)
                    251: {
                    252:     apr_status_t status;
                    253:     apr_off_t off = OFF_PAG(pagno);
                    254:     
                    255:     if ((status = apr_file_seek(db->pagf, APR_SET, &off)) == APR_SUCCESS)
                    256:         status = apr_file_write_full(db->pagf, buf, PBLKSIZ, NULL);
                    257: 
                    258:     return status;
                    259: }
                    260: 
                    261: APU_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, 
                    262:                                           const apr_sdbm_datum_t key)
                    263: {
                    264:     apr_status_t status;
                    265:     
                    266:     if (db == NULL || bad(key))
                    267:         return APR_EINVAL;
                    268:     if (apr_sdbm_rdonly(db))
                    269:         return APR_EINVAL;
                    270:     
                    271:     if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS)
                    272:         return status;
                    273: 
                    274:     if ((status = getpage(db, exhash(key))) == APR_SUCCESS) {
                    275:         if (!delpair(db->pagbuf, key))
                    276:             /* ### should we define some APRUTIL codes? */
1.3       paf       277:                        status = APR_SUCCESS; /* PAF: were APR_EGENERAL, contradicting comment in .h file :( */
1.1       paf       278:         else
                    279:             status = write_page(db, db->pagbuf, db->pagbno);
                    280:     }
                    281: 
                    282:     (void) apr_sdbm_unlock(db);
                    283: 
                    284:     return status;
                    285: }
                    286: 
                    287: APU_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key,
                    288:                                          apr_sdbm_datum_t val, int flags)
                    289: {
                    290:     int need;
                    291:     register long hash;
                    292:     apr_status_t status;
                    293:     
                    294:     if (db == NULL || bad(key))
                    295:         return APR_EINVAL;
                    296:     if (apr_sdbm_rdonly(db))
                    297:         return APR_EINVAL;
                    298:     need = key.dsize + val.dsize;
                    299:     /*
                    300:      * is the pair too big (or too small) for this database ??
                    301:      */
                    302:     if (need < 0 || need > PAIRMAX)
                    303:         return APR_EINVAL;
                    304: 
                    305:     if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS)
                    306:         return status;
                    307: 
                    308:     if ((status = getpage(db, (hash = exhash(key)))) == APR_SUCCESS) {
                    309: 
                    310:         /*
                    311:          * if we need to replace, delete the key/data pair
                    312:          * first. If it is not there, ignore.
                    313:          */
                    314:         if (flags == APR_SDBM_REPLACE)
                    315:             (void) delpair(db->pagbuf, key);
                    316:         else if (!(flags & APR_SDBM_INSERTDUP) && duppair(db->pagbuf, key)) {
                    317:             status = APR_EEXIST;
                    318:             goto error;
                    319:         }
                    320:         /*
                    321:          * if we do not have enough room, we have to split.
                    322:          */
                    323:         if (!fitpair(db->pagbuf, need))
                    324:             if ((status = makroom(db, hash, need)) != APR_SUCCESS)
                    325:                 goto error;
                    326:         /*
                    327:          * we have enough room or split is successful. insert the key,
                    328:          * and update the page file.
                    329:          */
                    330:         (void) putpair(db->pagbuf, key, val);
                    331: 
                    332:         status = write_page(db, db->pagbuf, db->pagbno);
                    333:     }
                    334: 
                    335: error:
                    336:     (void) apr_sdbm_unlock(db);    
                    337: 
                    338:     return status;
                    339: }
                    340: 
                    341: /*
                    342:  * makroom - make room by splitting the overfull page
                    343:  * this routine will attempt to make room for SPLTMAX times before
                    344:  * giving up.
                    345:  */
                    346: static apr_status_t makroom(apr_sdbm_t *db, long hash, int need)
                    347: {
                    348:     long newp;
                    349:     char twin[PBLKSIZ];
                    350:     char *pag = db->pagbuf;
                    351:     char *new = twin;
                    352:     register int smax = SPLTMAX;
                    353:     apr_status_t status;
                    354: 
                    355:     do {
                    356:         /*
                    357:          * split the current page
                    358:          */
                    359:         (void) splpage(pag, new, db->hmask + 1);
                    360:         /*
                    361:          * address of the new page
                    362:          */
                    363:         newp = (hash & db->hmask) | (db->hmask + 1);
                    364: 
                    365:         /*
                    366:          * write delay, read avoidence/cache shuffle:
                    367:          * select the page for incoming pair: if key is to go to the new page,
                    368:          * write out the previous one, and copy the new one over, thus making
                    369:          * it the current page. If not, simply write the new page, and we are
                    370:          * still looking at the page of interest. current page is not updated
                    371:          * here, as sdbm_store will do so, after it inserts the incoming pair.
                    372:          */
                    373:         if (hash & (db->hmask + 1)) {
                    374:             if ((status = write_page(db, db->pagbuf, db->pagbno)) 
                    375:                         != APR_SUCCESS)
                    376:                 return status;
                    377:                     
                    378:             db->pagbno = newp;
                    379:             (void) memcpy(pag, new, PBLKSIZ);
                    380:         }
                    381:         else {
                    382:             if ((status = write_page(db, new, newp)) != APR_SUCCESS)
                    383:                 return status;
                    384:         }
                    385: 
                    386:         if ((status = setdbit(db, db->curbit)) != APR_SUCCESS)
                    387:             return status;
                    388:         /*
                    389:          * see if we have enough room now
                    390:          */
                    391:         if (fitpair(pag, need))
                    392:             return APR_SUCCESS;
                    393:         /*
                    394:          * try again... update curbit and hmask as getpage would have
                    395:          * done. because of our update of the current page, we do not
                    396:          * need to read in anything. BUT we have to write the current
                    397:          * [deferred] page out, as the window of failure is too great.
                    398:          */
                    399:         db->curbit = 2 * db->curbit
                    400:                    + ((hash & (db->hmask + 1)) ? 2 : 1);
                    401:         db->hmask |= db->hmask + 1;
                    402:             
                    403:         if ((status = write_page(db, db->pagbuf, db->pagbno))
                    404:                     != APR_SUCCESS)
                    405:             return status;
                    406:             
                    407:     } while (--smax);
                    408: 
                    409:     /*
                    410:      * if we are here, this is real bad news. After SPLTMAX splits,
                    411:      * we still cannot fit the key. say goodnight.
                    412:      */
                    413: #if 0
                    414:     (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);
                    415: #endif
                    416:     /* ### ENOSPC not really appropriate but better than nothing */
                    417:     return APR_ENOSPC;
                    418: 
                    419: }
                    420: 
                    421: /* Reads 'len' bytes from file 'f' at offset 'off' into buf.
                    422:  * 'off' is given relative to the start of the file.
                    423:  * If EOF is returned while reading, this is taken as success.
                    424:  */
                    425: static apr_status_t read_from(apr_file_t *f, void *buf, 
                    426:              apr_off_t off, apr_size_t len)
                    427: {
                    428:     apr_status_t status;
                    429: 
                    430:     if ((status = apr_file_seek(f, APR_SET, &off)) != APR_SUCCESS ||
                    431:         ((status = apr_file_read_full(f, buf, len, NULL)) != APR_SUCCESS)) {
                    432:         /* if EOF is reached, pretend we read all zero's */
                    433:         if (status == APR_EOF) {
                    434:             memset(buf, 0, len);
                    435:             status = APR_SUCCESS;
                    436:         }
                    437:     }
                    438: 
                    439:     return status;
                    440: }
                    441: 
                    442: /*
                    443:  * the following two routines will break if
                    444:  * deletions aren't taken into account. (ndbm bug)
                    445:  */
                    446: APU_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, 
                    447:                                             apr_sdbm_datum_t *key)
                    448: {
                    449:     apr_status_t status;
                    450:     
                    451:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
                    452:         return status;
                    453: 
                    454:     /*
                    455:      * start at page 0
                    456:      */
                    457:     if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(0), PBLKSIZ))
                    458:                 == APR_SUCCESS) {
                    459:         db->pagbno = 0;
                    460:         db->blkptr = 0;
                    461:         db->keyptr = 0;
                    462:         status = getnext(key, db);
                    463:     }
                    464: 
                    465:     (void) apr_sdbm_unlock(db);
                    466: 
                    467:     return status;
                    468: }
                    469: 
                    470: APU_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, 
                    471:                                            apr_sdbm_datum_t *key)
                    472: {
                    473:     apr_status_t status;
                    474:     
                    475:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
                    476:         return status;
                    477: 
                    478:     status = getnext(key, db);
                    479: 
                    480:     (void) apr_sdbm_unlock(db);
                    481: 
                    482:     return status;
                    483: }
                    484: 
                    485: /*
                    486:  * all important binary tree traversal
                    487:  */
                    488: static apr_status_t getpage(apr_sdbm_t *db, long hash)
                    489: {
                    490:     register int hbit;
                    491:     register long dbit;
                    492:     register long pagb;
                    493:     apr_status_t status;
                    494: 
                    495:     dbit = 0;
                    496:     hbit = 0;
                    497:     while (dbit < db->maxbno && getdbit(db, dbit))
                    498:     dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1);
                    499: 
                    500:     debug(("dbit: %d...", dbit));
                    501: 
                    502:     db->curbit = dbit;
                    503:     db->hmask = masks[hbit];
                    504: 
                    505:     pagb = hash & db->hmask;
                    506:     /*
                    507:      * see if the block we need is already in memory.
                    508:      * note: this lookaside cache has about 10% hit rate.
                    509:      */
                    510:     if (pagb != db->pagbno) { 
                    511:         /*
                    512:          * note: here, we assume a "hole" is read as 0s.
                    513:          * if not, must zero pagbuf first.
                    514:          * ### joe: this assumption was surely never correct? but
                    515:          * ### we make it so in read_from anyway.
                    516:          */
                    517:         if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(pagb), PBLKSIZ)) 
                    518:                     != APR_SUCCESS)
                    519:             return status;
                    520: 
                    521:         if (!chkpage(db->pagbuf))
                    522:             return APR_ENOSPC; /* ### better error? */
                    523:         db->pagbno = pagb;
                    524: 
                    525:         debug(("pag read: %d\n", pagb));
                    526:     }
                    527:     return APR_SUCCESS;
                    528: }
                    529: 
                    530: static int getdbit(apr_sdbm_t *db, long dbit)
                    531: {
                    532:     register long c;
                    533:     register long dirb;
                    534: 
                    535:     c = dbit / BYTESIZ;
                    536:     dirb = c / DBLKSIZ;
                    537: 
                    538:     if (dirb != db->dirbno) {
                    539:         if (read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ)
                    540:                     != APR_SUCCESS)
                    541:             return 0;
                    542: 
                    543:         db->dirbno = dirb;
                    544: 
                    545:         debug(("dir read: %d\n", dirb));
                    546:     }
                    547: 
                    548:     return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ);
                    549: }
                    550: 
                    551: static apr_status_t setdbit(apr_sdbm_t *db, long dbit)
                    552: {
                    553:     register long c;
                    554:     register long dirb;
                    555:     apr_status_t status;
                    556:     apr_off_t off;
                    557: 
                    558:     c = dbit / BYTESIZ;
                    559:     dirb = c / DBLKSIZ;
                    560: 
                    561:     if (dirb != db->dirbno) {
                    562:         if ((status = read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ))
                    563:                     != APR_SUCCESS)
                    564:             return status;
                    565: 
                    566:         db->dirbno = dirb;
                    567:         
                    568:         debug(("dir read: %d\n", dirb));
                    569:     }
                    570: 
                    571:     db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ);
                    572: 
                    573:     if (dbit >= db->maxbno)
                    574:         db->maxbno += DBLKSIZ * BYTESIZ;
                    575: 
                    576:     off = OFF_DIR(dirb);
                    577:     if ((status = apr_file_seek(db->dirf, APR_SET, &off)) == APR_SUCCESS)
                    578:         status = apr_file_write_full(db->dirf, db->dirbuf, DBLKSIZ, NULL);
                    579: 
                    580:     return status;
                    581: }
                    582: 
                    583: /*
                    584: * getnext - get the next key in the page, and if done with
                    585: * the page, try the next page in sequence
                    586: */
                    587: static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db)
                    588: {
                    589:     apr_status_t status;
                    590:     for (;;) {
                    591:         db->keyptr++;
                    592:         *key = getnkey(db->pagbuf, db->keyptr);
                    593:         if (key->dptr != NULL)
                    594:             return APR_SUCCESS;
                    595:         /*
                    596:          * we either run out, or there is nothing on this page..
                    597:          * try the next one... If we lost our position on the
                    598:          * file, we will have to seek.
                    599:          */
                    600:         db->keyptr = 0;
                    601:         if (db->pagbno != db->blkptr++) {
                    602:             apr_off_t off = OFF_PAG(db->blkptr);
                    603:             if ((status = apr_file_seek(db->pagf, APR_SET, &off) 
                    604:                         != APR_SUCCESS))
                    605:                 return status;
                    606:         }
                    607: 
                    608:         db->pagbno = db->blkptr;
                    609:         /* ### EOF acceptable here too? */
                    610:         if ((status = apr_file_read_full(db->pagf, db->pagbuf, PBLKSIZ, NULL))
                    611:                     != APR_SUCCESS)
                    612:             return status;
                    613:         if (!chkpage(db->pagbuf))
                    614:             return APR_EGENERAL;     /* ### need better error */
                    615:     }
                    616: 
                    617:     /* NOTREACHED */
                    618: }
                    619: 
                    620: 
                    621: APU_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db)
                    622: {
                    623:     /* ### Should we return true if the first lock is a share lock,
                    624:      *     to reflect that apr_sdbm_store and apr_sdbm_delete will fail?
                    625:      */
                    626:     return (db->flags & SDBM_RDONLY) != 0;
                    627: }
                    628: 

E-mail: