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

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() */
        !            74: #include <stdlib.h>     /* for malloc() and free() */
        !            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);
        !           123:     free(db);
        !           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: 
        !           136:     db = malloc(sizeof(*db));
        !           137:     memset(db, 0, sizeof(*db));
        !           138: 
        !           139:     db->pool = p;
        !           140: 
        !           141:     /*
        !           142:      * adjust user flags so that WRONLY becomes RDWR, 
        !           143:      * as required by this package. Also set our internal
        !           144:      * flag for RDONLY if needed.
        !           145:      */
        !           146:     if (!(flags & APR_WRITE)) {
        !           147:         db->flags |= SDBM_RDONLY;
        !           148:     }
        !           149: 
        !           150:     /*
        !           151:      * adjust the file open flags so that we handle locking
        !           152:      * on our own (don't rely on any locking behavior within
        !           153:      * an apr_file_t, in case it's ever introduced, and set
        !           154:      * our own flag.
        !           155:      */
        !           156:     if (flags & APR_SHARELOCK) {
        !           157:         db->flags |= SDBM_SHARED;
        !           158:         flags &= ~APR_SHARELOCK;
        !           159:     }
        !           160: 
        !           161:     flags |= APR_BINARY | APR_READ;
        !           162: 
        !           163:     /*
        !           164:      * open the files in sequence, and stat the dirfile.
        !           165:      * If we fail anywhere, undo everything, return NULL.
        !           166:      */
        !           167: 
        !           168:     if ((status = apr_file_open(&db->dirf, dirname, flags, perms, p))
        !           169:                 != APR_SUCCESS)
        !           170:         goto error;
        !           171: 
        !           172:     if ((status = apr_file_open(&db->pagf, pagname, flags, perms, p))
        !           173:                 != APR_SUCCESS)
        !           174:         goto error;
        !           175: 
        !           176:     if ((status = apr_sdbm_lock(db, (db->flags & SDBM_RDONLY) 
        !           177:                                         ? APR_FLOCK_SHARED
        !           178:                                         : APR_FLOCK_EXCLUSIVE))
        !           179:                 != APR_SUCCESS)
        !           180:         goto error;
        !           181: 
        !           182:     /* apr_pcalloc zeroed the buffers
        !           183:      * apr_sdbm_lock stated the dirf->size and invalidated the cache
        !           184:      */
        !           185: 
        !           186:     /*
        !           187:      * if we are opened in SHARED mode, unlock ourself 
        !           188:      */
        !           189:     if (db->flags & SDBM_SHARED)
        !           190:         if ((status = apr_sdbm_unlock(db)) != APR_SUCCESS)
        !           191:             goto error;
        !           192: 
        !           193:     /* make sure that we close the database at some point */
        !           194:     apr_pool_cleanup_register(p, db, database_cleanup, apr_pool_cleanup_null);
        !           195: 
        !           196:     /* Done! */
        !           197:     *pdb = db;
        !           198:     return APR_SUCCESS;
        !           199: 
        !           200: error:
        !           201:     if (db->dirf && db->pagf)
        !           202:         (void) apr_sdbm_unlock(db);
        !           203:     if (db->dirf != NULL)
        !           204:         (void) apr_file_close(db->dirf);
        !           205:     if (db->pagf != NULL) {
        !           206:         (void) apr_file_close(db->pagf);
        !           207:     }
        !           208:     free(db);
        !           209:     return status;
        !           210: }
        !           211: 
        !           212: APU_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *file, 
        !           213:                                         apr_int32_t flags, 
        !           214:                                         apr_fileperms_t perms, apr_pool_t *p)
        !           215: {
        !           216:     char *dirname = apr_pstrcat(p, file, APR_SDBM_DIRFEXT, NULL);
        !           217:     char *pagname = apr_pstrcat(p, file, APR_SDBM_PAGFEXT, NULL);
        !           218:     
        !           219:     return prep(db, dirname, pagname, flags, perms, p);
        !           220: }
        !           221: 
        !           222: APU_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db)
        !           223: {
        !           224:     return apr_pool_cleanup_run(db->pool, db, database_cleanup);
        !           225: }
        !           226: 
        !           227: APU_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, apr_sdbm_datum_t *val,
        !           228:                                          apr_sdbm_datum_t key)
        !           229: {
        !           230:     apr_status_t status;
        !           231:     
        !           232:     if (db == NULL || bad(key))
        !           233:         return APR_EINVAL;
        !           234: 
        !           235:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
        !           236:         return status;
        !           237: 
        !           238:     if ((status = getpage(db, exhash(key))) == APR_SUCCESS) {
        !           239:         *val = getpair(db->pagbuf, key);
        !           240:         /* ### do we want a not-found result? */
        !           241:     }
        !           242: 
        !           243:     (void) apr_sdbm_unlock(db);
        !           244: 
        !           245:     return status;
        !           246: }
        !           247: 
        !           248: static apr_status_t write_page(apr_sdbm_t *db, const char *buf, long pagno)
        !           249: {
        !           250:     apr_status_t status;
        !           251:     apr_off_t off = OFF_PAG(pagno);
        !           252:     
        !           253:     if ((status = apr_file_seek(db->pagf, APR_SET, &off)) == APR_SUCCESS)
        !           254:         status = apr_file_write_full(db->pagf, buf, PBLKSIZ, NULL);
        !           255: 
        !           256:     return status;
        !           257: }
        !           258: 
        !           259: APU_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, 
        !           260:                                           const apr_sdbm_datum_t key)
        !           261: {
        !           262:     apr_status_t status;
        !           263:     
        !           264:     if (db == NULL || bad(key))
        !           265:         return APR_EINVAL;
        !           266:     if (apr_sdbm_rdonly(db))
        !           267:         return APR_EINVAL;
        !           268:     
        !           269:     if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS)
        !           270:         return status;
        !           271: 
        !           272:     if ((status = getpage(db, exhash(key))) == APR_SUCCESS) {
        !           273:         if (!delpair(db->pagbuf, key))
        !           274:             /* ### should we define some APRUTIL codes? */
        !           275:             status = APR_EGENERAL;
        !           276:         else
        !           277:             status = write_page(db, db->pagbuf, db->pagbno);
        !           278:     }
        !           279: 
        !           280:     (void) apr_sdbm_unlock(db);
        !           281: 
        !           282:     return status;
        !           283: }
        !           284: 
        !           285: APU_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key,
        !           286:                                          apr_sdbm_datum_t val, int flags)
        !           287: {
        !           288:     int need;
        !           289:     register long hash;
        !           290:     apr_status_t status;
        !           291:     
        !           292:     if (db == NULL || bad(key))
        !           293:         return APR_EINVAL;
        !           294:     if (apr_sdbm_rdonly(db))
        !           295:         return APR_EINVAL;
        !           296:     need = key.dsize + val.dsize;
        !           297:     /*
        !           298:      * is the pair too big (or too small) for this database ??
        !           299:      */
        !           300:     if (need < 0 || need > PAIRMAX)
        !           301:         return APR_EINVAL;
        !           302: 
        !           303:     if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS)
        !           304:         return status;
        !           305: 
        !           306:     if ((status = getpage(db, (hash = exhash(key)))) == APR_SUCCESS) {
        !           307: 
        !           308:         /*
        !           309:          * if we need to replace, delete the key/data pair
        !           310:          * first. If it is not there, ignore.
        !           311:          */
        !           312:         if (flags == APR_SDBM_REPLACE)
        !           313:             (void) delpair(db->pagbuf, key);
        !           314:         else if (!(flags & APR_SDBM_INSERTDUP) && duppair(db->pagbuf, key)) {
        !           315:             status = APR_EEXIST;
        !           316:             goto error;
        !           317:         }
        !           318:         /*
        !           319:          * if we do not have enough room, we have to split.
        !           320:          */
        !           321:         if (!fitpair(db->pagbuf, need))
        !           322:             if ((status = makroom(db, hash, need)) != APR_SUCCESS)
        !           323:                 goto error;
        !           324:         /*
        !           325:          * we have enough room or split is successful. insert the key,
        !           326:          * and update the page file.
        !           327:          */
        !           328:         (void) putpair(db->pagbuf, key, val);
        !           329: 
        !           330:         status = write_page(db, db->pagbuf, db->pagbno);
        !           331:     }
        !           332: 
        !           333: error:
        !           334:     (void) apr_sdbm_unlock(db);    
        !           335: 
        !           336:     return status;
        !           337: }
        !           338: 
        !           339: /*
        !           340:  * makroom - make room by splitting the overfull page
        !           341:  * this routine will attempt to make room for SPLTMAX times before
        !           342:  * giving up.
        !           343:  */
        !           344: static apr_status_t makroom(apr_sdbm_t *db, long hash, int need)
        !           345: {
        !           346:     long newp;
        !           347:     char twin[PBLKSIZ];
        !           348:     char *pag = db->pagbuf;
        !           349:     char *new = twin;
        !           350:     register int smax = SPLTMAX;
        !           351:     apr_status_t status;
        !           352: 
        !           353:     do {
        !           354:         /*
        !           355:          * split the current page
        !           356:          */
        !           357:         (void) splpage(pag, new, db->hmask + 1);
        !           358:         /*
        !           359:          * address of the new page
        !           360:          */
        !           361:         newp = (hash & db->hmask) | (db->hmask + 1);
        !           362: 
        !           363:         /*
        !           364:          * write delay, read avoidence/cache shuffle:
        !           365:          * select the page for incoming pair: if key is to go to the new page,
        !           366:          * write out the previous one, and copy the new one over, thus making
        !           367:          * it the current page. If not, simply write the new page, and we are
        !           368:          * still looking at the page of interest. current page is not updated
        !           369:          * here, as sdbm_store will do so, after it inserts the incoming pair.
        !           370:          */
        !           371:         if (hash & (db->hmask + 1)) {
        !           372:             if ((status = write_page(db, db->pagbuf, db->pagbno)) 
        !           373:                         != APR_SUCCESS)
        !           374:                 return status;
        !           375:                     
        !           376:             db->pagbno = newp;
        !           377:             (void) memcpy(pag, new, PBLKSIZ);
        !           378:         }
        !           379:         else {
        !           380:             if ((status = write_page(db, new, newp)) != APR_SUCCESS)
        !           381:                 return status;
        !           382:         }
        !           383: 
        !           384:         if ((status = setdbit(db, db->curbit)) != APR_SUCCESS)
        !           385:             return status;
        !           386:         /*
        !           387:          * see if we have enough room now
        !           388:          */
        !           389:         if (fitpair(pag, need))
        !           390:             return APR_SUCCESS;
        !           391:         /*
        !           392:          * try again... update curbit and hmask as getpage would have
        !           393:          * done. because of our update of the current page, we do not
        !           394:          * need to read in anything. BUT we have to write the current
        !           395:          * [deferred] page out, as the window of failure is too great.
        !           396:          */
        !           397:         db->curbit = 2 * db->curbit
        !           398:                    + ((hash & (db->hmask + 1)) ? 2 : 1);
        !           399:         db->hmask |= db->hmask + 1;
        !           400:             
        !           401:         if ((status = write_page(db, db->pagbuf, db->pagbno))
        !           402:                     != APR_SUCCESS)
        !           403:             return status;
        !           404:             
        !           405:     } while (--smax);
        !           406: 
        !           407:     /*
        !           408:      * if we are here, this is real bad news. After SPLTMAX splits,
        !           409:      * we still cannot fit the key. say goodnight.
        !           410:      */
        !           411: #if 0
        !           412:     (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);
        !           413: #endif
        !           414:     /* ### ENOSPC not really appropriate but better than nothing */
        !           415:     return APR_ENOSPC;
        !           416: 
        !           417: }
        !           418: 
        !           419: /* Reads 'len' bytes from file 'f' at offset 'off' into buf.
        !           420:  * 'off' is given relative to the start of the file.
        !           421:  * If EOF is returned while reading, this is taken as success.
        !           422:  */
        !           423: static apr_status_t read_from(apr_file_t *f, void *buf, 
        !           424:              apr_off_t off, apr_size_t len)
        !           425: {
        !           426:     apr_status_t status;
        !           427: 
        !           428:     if ((status = apr_file_seek(f, APR_SET, &off)) != APR_SUCCESS ||
        !           429:         ((status = apr_file_read_full(f, buf, len, NULL)) != APR_SUCCESS)) {
        !           430:         /* if EOF is reached, pretend we read all zero's */
        !           431:         if (status == APR_EOF) {
        !           432:             memset(buf, 0, len);
        !           433:             status = APR_SUCCESS;
        !           434:         }
        !           435:     }
        !           436: 
        !           437:     return status;
        !           438: }
        !           439: 
        !           440: /*
        !           441:  * the following two routines will break if
        !           442:  * deletions aren't taken into account. (ndbm bug)
        !           443:  */
        !           444: APU_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, 
        !           445:                                             apr_sdbm_datum_t *key)
        !           446: {
        !           447:     apr_status_t status;
        !           448:     
        !           449:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
        !           450:         return status;
        !           451: 
        !           452:     /*
        !           453:      * start at page 0
        !           454:      */
        !           455:     if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(0), PBLKSIZ))
        !           456:                 == APR_SUCCESS) {
        !           457:         db->pagbno = 0;
        !           458:         db->blkptr = 0;
        !           459:         db->keyptr = 0;
        !           460:         status = getnext(key, db);
        !           461:     }
        !           462: 
        !           463:     (void) apr_sdbm_unlock(db);
        !           464: 
        !           465:     return status;
        !           466: }
        !           467: 
        !           468: APU_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, 
        !           469:                                            apr_sdbm_datum_t *key)
        !           470: {
        !           471:     apr_status_t status;
        !           472:     
        !           473:     if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS)
        !           474:         return status;
        !           475: 
        !           476:     status = getnext(key, db);
        !           477: 
        !           478:     (void) apr_sdbm_unlock(db);
        !           479: 
        !           480:     return status;
        !           481: }
        !           482: 
        !           483: /*
        !           484:  * all important binary tree traversal
        !           485:  */
        !           486: static apr_status_t getpage(apr_sdbm_t *db, long hash)
        !           487: {
        !           488:     register int hbit;
        !           489:     register long dbit;
        !           490:     register long pagb;
        !           491:     apr_status_t status;
        !           492: 
        !           493:     dbit = 0;
        !           494:     hbit = 0;
        !           495:     while (dbit < db->maxbno && getdbit(db, dbit))
        !           496:     dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1);
        !           497: 
        !           498:     debug(("dbit: %d...", dbit));
        !           499: 
        !           500:     db->curbit = dbit;
        !           501:     db->hmask = masks[hbit];
        !           502: 
        !           503:     pagb = hash & db->hmask;
        !           504:     /*
        !           505:      * see if the block we need is already in memory.
        !           506:      * note: this lookaside cache has about 10% hit rate.
        !           507:      */
        !           508:     if (pagb != db->pagbno) { 
        !           509:         /*
        !           510:          * note: here, we assume a "hole" is read as 0s.
        !           511:          * if not, must zero pagbuf first.
        !           512:          * ### joe: this assumption was surely never correct? but
        !           513:          * ### we make it so in read_from anyway.
        !           514:          */
        !           515:         if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(pagb), PBLKSIZ)) 
        !           516:                     != APR_SUCCESS)
        !           517:             return status;
        !           518: 
        !           519:         if (!chkpage(db->pagbuf))
        !           520:             return APR_ENOSPC; /* ### better error? */
        !           521:         db->pagbno = pagb;
        !           522: 
        !           523:         debug(("pag read: %d\n", pagb));
        !           524:     }
        !           525:     return APR_SUCCESS;
        !           526: }
        !           527: 
        !           528: static int getdbit(apr_sdbm_t *db, long dbit)
        !           529: {
        !           530:     register long c;
        !           531:     register long dirb;
        !           532: 
        !           533:     c = dbit / BYTESIZ;
        !           534:     dirb = c / DBLKSIZ;
        !           535: 
        !           536:     if (dirb != db->dirbno) {
        !           537:         if (read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ)
        !           538:                     != APR_SUCCESS)
        !           539:             return 0;
        !           540: 
        !           541:         db->dirbno = dirb;
        !           542: 
        !           543:         debug(("dir read: %d\n", dirb));
        !           544:     }
        !           545: 
        !           546:     return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ);
        !           547: }
        !           548: 
        !           549: static apr_status_t setdbit(apr_sdbm_t *db, long dbit)
        !           550: {
        !           551:     register long c;
        !           552:     register long dirb;
        !           553:     apr_status_t status;
        !           554:     apr_off_t off;
        !           555: 
        !           556:     c = dbit / BYTESIZ;
        !           557:     dirb = c / DBLKSIZ;
        !           558: 
        !           559:     if (dirb != db->dirbno) {
        !           560:         if ((status = read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ))
        !           561:                     != APR_SUCCESS)
        !           562:             return status;
        !           563: 
        !           564:         db->dirbno = dirb;
        !           565:         
        !           566:         debug(("dir read: %d\n", dirb));
        !           567:     }
        !           568: 
        !           569:     db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ);
        !           570: 
        !           571:     if (dbit >= db->maxbno)
        !           572:         db->maxbno += DBLKSIZ * BYTESIZ;
        !           573: 
        !           574:     off = OFF_DIR(dirb);
        !           575:     if ((status = apr_file_seek(db->dirf, APR_SET, &off)) == APR_SUCCESS)
        !           576:         status = apr_file_write_full(db->dirf, db->dirbuf, DBLKSIZ, NULL);
        !           577: 
        !           578:     return status;
        !           579: }
        !           580: 
        !           581: /*
        !           582: * getnext - get the next key in the page, and if done with
        !           583: * the page, try the next page in sequence
        !           584: */
        !           585: static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db)
        !           586: {
        !           587:     apr_status_t status;
        !           588:     for (;;) {
        !           589:         db->keyptr++;
        !           590:         *key = getnkey(db->pagbuf, db->keyptr);
        !           591:         if (key->dptr != NULL)
        !           592:             return APR_SUCCESS;
        !           593:         /*
        !           594:          * we either run out, or there is nothing on this page..
        !           595:          * try the next one... If we lost our position on the
        !           596:          * file, we will have to seek.
        !           597:          */
        !           598:         db->keyptr = 0;
        !           599:         if (db->pagbno != db->blkptr++) {
        !           600:             apr_off_t off = OFF_PAG(db->blkptr);
        !           601:             if ((status = apr_file_seek(db->pagf, APR_SET, &off) 
        !           602:                         != APR_SUCCESS))
        !           603:                 return status;
        !           604:         }
        !           605: 
        !           606:         db->pagbno = db->blkptr;
        !           607:         /* ### EOF acceptable here too? */
        !           608:         if ((status = apr_file_read_full(db->pagf, db->pagbuf, PBLKSIZ, NULL))
        !           609:                     != APR_SUCCESS)
        !           610:             return status;
        !           611:         if (!chkpage(db->pagbuf))
        !           612:             return APR_EGENERAL;     /* ### need better error */
        !           613:     }
        !           614: 
        !           615:     /* NOTREACHED */
        !           616: }
        !           617: 
        !           618: 
        !           619: APU_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db)
        !           620: {
        !           621:     /* ### Should we return true if the first lock is a share lock,
        !           622:      *     to reflect that apr_sdbm_store and apr_sdbm_delete will fail?
        !           623:      */
        !           624:     return (db->flags & SDBM_RDONLY) != 0;
        !           625: }
        !           626: 

E-mail: