Annotation of qemu/roms/openbios/fs/hfs/block.c, revision 1.1

1.1     ! root        1: /*
        !             2: * libhfs - library for reading and writing Macintosh HFS volumes
        !             3: * Copyright (C) 1996-1998 Robert Leslie
        !             4: *
        !             5: * This program is free software; you can redistribute it and/or modify
        !             6: * it under the terms of the GNU General Public License as published by
        !             7: * the Free Software Foundation; either version 2 of the License, or
        !             8: * (at your option) any later version.
        !             9: *
        !            10: * This program is distributed in the hope that it will be useful,
        !            11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            13: * GNU General Public License for more details.
        !            14: *
        !            15: * You should have received a copy of the GNU General Public License
        !            16: * along with this program; if not, write to the Free Software
        !            17: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
        !            18: * MA 02110-1301, USA.
        !            19: *
        !            20: * $Id: block.c,v 1.11 1998/11/02 22:08:52 rob Exp $
        !            21: */
        !            22: 
        !            23: #include "config.h"
        !            24: 
        !            25: #include "libhfs.h"
        !            26: #include "volume.h"
        !            27: #include "block.h"
        !            28: #include "os.h"
        !            29: 
        !            30: #define INUSE(b)       ((b)->flags & HFS_BUCKET_INUSE)
        !            31: #define DIRTY(b)       ((b)->flags & HFS_BUCKET_DIRTY)
        !            32: 
        !            33: /*
        !            34:  * NAME:       block->init()
        !            35:  * DESCRIPTION:        initialize a volume's block cache
        !            36:  */
        !            37: int b_init(hfsvol *vol)
        !            38: {
        !            39:   bcache *cache;
        !            40:   int i;
        !            41: 
        !            42:   ASSERT(vol->cache == 0);
        !            43: 
        !            44:   cache = ALLOC(bcache, 1);
        !            45:   if (cache == NULL)
        !            46:     ERROR(ENOMEM, NULL);
        !            47: 
        !            48:   vol->cache = cache;
        !            49: 
        !            50:   cache->vol    = vol;
        !            51:   cache->tail   = &cache->chain[HFS_CACHESZ - 1];
        !            52: 
        !            53:   cache->hits   = 0;
        !            54:   cache->misses = 0;
        !            55: 
        !            56:   for (i = 0; i < HFS_CACHESZ; ++i)
        !            57:     {
        !            58:       bucket *b = &cache->chain[i];
        !            59: 
        !            60:       b->flags = 0;
        !            61:       b->count = 0;
        !            62: 
        !            63:       b->bnum  = 0;
        !            64:       b->data  = &cache->pool[i];
        !            65: 
        !            66:       b->cnext = b + 1;
        !            67:       b->cprev = b - 1;
        !            68: 
        !            69:       b->hnext = NULL;
        !            70:       b->hprev = NULL;
        !            71:     }
        !            72: 
        !            73:   cache->chain[0].cprev = cache->tail;
        !            74:   cache->tail->cnext    = &cache->chain[0];
        !            75: 
        !            76:   for (i = 0; i < HFS_HASHSZ; ++i)
        !            77:     cache->hash[i] = NULL;
        !            78: 
        !            79:   return 0;
        !            80: 
        !            81: fail:
        !            82:   return -1;
        !            83: }
        !            84: 
        !            85: # ifdef DEBUG
        !            86: /*
        !            87:  * NAME:       block->showstats()
        !            88:  * DESCRIPTION:        output cache hit/miss ratio
        !            89:  */
        !            90: void b_showstats(const bcache *cache)
        !            91: {
        !            92:   fprintf(stderr, "BLOCK: CACHE vol 0x%lx \"%s\" hit/miss ratio = %.3f\n",
        !            93:          (unsigned long) cache->vol, cache->vol->mdb.drVN,
        !            94:          (float) cache->hits / (float) cache->misses);
        !            95: }
        !            96: 
        !            97: /*
        !            98:  * NAME:       block->dumpcache()
        !            99:  * DESCRIPTION:        dump the cache tables for a volume
        !           100:  */
        !           101: void b_dumpcache(const bcache *cache)
        !           102: {
        !           103:   const bucket *b;
        !           104:   int i;
        !           105: 
        !           106:   fprintf(stderr, "BLOCK CACHE DUMP:\n");
        !           107: 
        !           108:   for (i = 0, b = cache->tail->cnext; i < HFS_CACHESZ; ++i, b = b->cnext)
        !           109:     {
        !           110:       if (INUSE(b))
        !           111:        {
        !           112:          fprintf(stderr, "\t %lu", b->bnum);
        !           113:          if (DIRTY(b))
        !           114:            fprintf(stderr, "*");
        !           115: 
        !           116:          fprintf(stderr, ":%u", b->count);
        !           117:        }
        !           118:     }
        !           119: 
        !           120:   fprintf(stderr, "\n");
        !           121: 
        !           122:   fprintf(stderr, "BLOCK HASH DUMP:\n");
        !           123: 
        !           124:   for (i = 0; i < HFS_HASHSZ; ++i)
        !           125:     {
        !           126:       int seen = 0;
        !           127: 
        !           128:       for (b = cache->hash[i]; b; b = b->hnext)
        !           129:        {
        !           130:          if (! seen)
        !           131:            fprintf(stderr, "  %d:", i);
        !           132: 
        !           133:          if (INUSE(b))
        !           134:            {
        !           135:              fprintf(stderr, " %lu", b->bnum);
        !           136:              if (DIRTY(b))
        !           137:                fprintf(stderr, "*");
        !           138: 
        !           139:              fprintf(stderr, ":%u", b->count);
        !           140:            }
        !           141: 
        !           142:          seen = 1;
        !           143:        }
        !           144: 
        !           145:       if (seen)
        !           146:        fprintf(stderr, "\n");
        !           147:     }
        !           148: }
        !           149: # endif
        !           150: 
        !           151: /*
        !           152:  * NAME:       fillchain()
        !           153:  * DESCRIPTION:        fill a chain of bucket buffers with a single read
        !           154:  */
        !           155: static
        !           156: int fillchain(hfsvol *vol, bucket **bptr, unsigned int *count)
        !           157: {
        !           158:   bucket *blist[HFS_BLOCKBUFSZ], **start = bptr;
        !           159:   unsigned long bnum=-2;       // XXX
        !           160:   unsigned int len, i;
        !           161: 
        !           162:   for (len = 0; len < HFS_BLOCKBUFSZ &&
        !           163:         (unsigned int) (bptr - start) < *count; ++bptr)
        !           164:     {
        !           165:       if (INUSE(*bptr))
        !           166:        continue;
        !           167: 
        !           168:       if (len > 0 && (*bptr)->bnum != bnum)
        !           169:        break;
        !           170: 
        !           171:       blist[len++] = *bptr;
        !           172:       bnum = (*bptr)->bnum + 1;
        !           173:     }
        !           174: 
        !           175:   *count = bptr - start;
        !           176: 
        !           177:   if (len == 0)
        !           178:     goto done;
        !           179:   else if (len == 1)
        !           180:     {
        !           181:       if (b_readpb(vol, vol->vstart + blist[0]->bnum,
        !           182:                   blist[0]->data, 1) == -1)
        !           183:        goto fail;
        !           184:     }
        !           185:   else
        !           186:     {
        !           187:       block buffer[HFS_BLOCKBUFSZ];
        !           188: 
        !           189:       if (b_readpb(vol, vol->vstart + blist[0]->bnum, buffer, len) == -1)
        !           190:        goto fail;
        !           191: 
        !           192:       for (i = 0; i < len; ++i)
        !           193:        memcpy(blist[i]->data, buffer[i], HFS_BLOCKSZ);
        !           194:     }
        !           195: 
        !           196:   for (i = 0; i < len; ++i)
        !           197:     {
        !           198:       blist[i]->flags |=  HFS_BUCKET_INUSE;
        !           199:       blist[i]->flags &= ~HFS_BUCKET_DIRTY;
        !           200:     }
        !           201: 
        !           202: done:
        !           203:   return 0;
        !           204: 
        !           205: fail:
        !           206:   return -1;
        !           207: }
        !           208: 
        !           209: 
        !           210: /*
        !           211:  * NAME:       compare()
        !           212:  * DESCRIPTION:        comparison function for qsort of cache bucket pointers
        !           213:  */
        !           214: static
        !           215: int compare(const bucket **b1, const bucket **b2)
        !           216: {
        !           217:   long diff;
        !           218: 
        !           219:   diff = (*b1)->bnum - (*b2)->bnum;
        !           220: 
        !           221:   if (diff < 0)
        !           222:     return -1;
        !           223:   else if (diff > 0)
        !           224:     return 1;
        !           225:   else
        !           226:     return 0;
        !           227: }
        !           228: 
        !           229: /*
        !           230:  * NAME:       dobuckets()
        !           231:  * DESCRIPTION:        fill or flush an array of cache buckets to a volume
        !           232:  */
        !           233: static
        !           234: int dobuckets(hfsvol *vol, bucket **chain, unsigned int len,
        !           235:              int (*func)(hfsvol *, bucket **, unsigned int *))
        !           236: {
        !           237:   unsigned int count, i;
        !           238:   int result = 0;
        !           239: 
        !           240:   qsort(chain, len, sizeof(*chain),
        !           241:        (int (*)(const void *, const void *)) compare);
        !           242: 
        !           243:   for (i = 0; i < len; i += count)
        !           244:     {
        !           245:       count = len - i;
        !           246:       if (func(vol, chain + i, &count) == -1)
        !           247:        result = -1;
        !           248:     }
        !           249: 
        !           250:   return result;
        !           251: }
        !           252: 
        !           253: # define fillbuckets(vol, chain, len)  dobuckets(vol, chain, len, fillchain)
        !           254: 
        !           255: /*
        !           256:  * NAME:       block->finish()
        !           257:  * DESCRIPTION:        commit and free a volume's block cache
        !           258:  */
        !           259: int b_finish(hfsvol *vol)
        !           260: {
        !           261:   int result = 0;
        !           262: 
        !           263:   if (vol->cache == NULL)
        !           264:     goto done;
        !           265: 
        !           266: # ifdef DEBUG
        !           267:   b_dumpcache(vol->cache);
        !           268: # endif
        !           269: 
        !           270:   FREE(vol->cache);
        !           271:   vol->cache = NULL;
        !           272: 
        !           273: done:
        !           274:   return result;
        !           275: }
        !           276: 
        !           277: /*
        !           278:  * NAME:       findbucket()
        !           279:  * DESCRIPTION:        locate a bucket in the cache, and/or its hash slot
        !           280:  */
        !           281: static
        !           282: bucket *findbucket(bcache *cache, unsigned long bnum, bucket ***hslot)
        !           283: {
        !           284:   bucket *b;
        !           285: 
        !           286:   *hslot = &cache->hash[bnum & (HFS_HASHSZ - 1)];
        !           287: 
        !           288:   for (b = **hslot; b; b = b->hnext)
        !           289:     {
        !           290:       if (INUSE(b) && b->bnum == bnum)
        !           291:        break;
        !           292:     }
        !           293: 
        !           294:   return b;
        !           295: }
        !           296: 
        !           297: /*
        !           298:  * NAME:       reuse()
        !           299:  * DESCRIPTION:        free a bucket for reuse, flushing if necessary
        !           300:  */
        !           301: static
        !           302: int reuse(bcache *cache, bucket *b, unsigned long bnum)
        !           303: {
        !           304:   bucket *bptr;
        !           305:   int i;
        !           306: 
        !           307: # ifdef DEBUG
        !           308:   if (INUSE(b))
        !           309:     fprintf(stderr, "BLOCK: CACHE reusing bucket containing "
        !           310:            "vol 0x%lx block %lu:%u\n",
        !           311:            (unsigned long) cache->vol, b->bnum, b->count);
        !           312: # endif
        !           313: 
        !           314:   if (INUSE(b) && DIRTY(b))
        !           315:     {
        !           316:       /* flush most recently unused buckets */
        !           317: 
        !           318:       for (bptr = b, i = 0; i < HFS_BLOCKBUFSZ; ++i)
        !           319:        {
        !           320:          bptr = bptr->cprev;
        !           321:        }
        !           322:     }
        !           323: 
        !           324:   b->flags &= ~HFS_BUCKET_INUSE;
        !           325:   b->count  = 1;
        !           326:   b->bnum   = bnum;
        !           327: 
        !           328:   return 0;
        !           329: }
        !           330: 
        !           331: /*
        !           332:  * NAME:       cplace()
        !           333:  * DESCRIPTION:        move a bucket to an appropriate place near head of the chain
        !           334:  */
        !           335: static
        !           336: void cplace(bcache *cache, bucket *b)
        !           337: {
        !           338:   bucket *p;
        !           339: 
        !           340:   for (p = cache->tail->cnext; p->count > 1; p = p->cnext)
        !           341:     --p->count;
        !           342: 
        !           343:   b->cnext->cprev = b->cprev;
        !           344:   b->cprev->cnext = b->cnext;
        !           345: 
        !           346:   if (cache->tail == b)
        !           347:     cache->tail = b->cprev;
        !           348: 
        !           349:   b->cprev = p->cprev;
        !           350:   b->cnext = p;
        !           351: 
        !           352:   p->cprev->cnext = b;
        !           353:   p->cprev = b;
        !           354: }
        !           355: 
        !           356: /*
        !           357:  * NAME:       hplace()
        !           358:  * DESCRIPTION:        move a bucket to the head of its hash slot
        !           359:  */
        !           360: static
        !           361: void hplace(bucket **hslot, bucket *b)
        !           362: {
        !           363:   if (*hslot != b)
        !           364:     {
        !           365:       if (b->hprev)
        !           366:        *b->hprev = b->hnext;
        !           367:       if (b->hnext)
        !           368:        b->hnext->hprev = b->hprev;
        !           369: 
        !           370:       b->hprev = hslot;
        !           371:       b->hnext = *hslot;
        !           372: 
        !           373:       if (*hslot)
        !           374:        (*hslot)->hprev = &b->hnext;
        !           375: 
        !           376:       *hslot = b;
        !           377:     }
        !           378: }
        !           379: 
        !           380: /*
        !           381:  * NAME:       getbucket()
        !           382:  * DESCRIPTION:        fetch a bucket from the cache, or an empty one to be filled
        !           383:  */
        !           384: static
        !           385: bucket *getbucket(bcache *cache, unsigned long bnum, int fill)
        !           386: {
        !           387:   bucket **hslot, *b, *p, *bptr,
        !           388:     *chain[HFS_BLOCKBUFSZ], **slots[HFS_BLOCKBUFSZ];
        !           389: 
        !           390:   b = findbucket(cache, bnum, &hslot);
        !           391: 
        !           392:   if (b)
        !           393:     {
        !           394:       /* cache hit; move towards head of cache chain */
        !           395: 
        !           396:       ++cache->hits;
        !           397: 
        !           398:       if (++b->count > b->cprev->count &&
        !           399:          b != cache->tail->cnext)
        !           400:        {
        !           401:          p = b->cprev;
        !           402: 
        !           403:          p->cprev->cnext = b;
        !           404:          b->cnext->cprev = p;
        !           405: 
        !           406:          p->cnext = b->cnext;
        !           407:          b->cprev = p->cprev;
        !           408: 
        !           409:          p->cprev = b;
        !           410:          b->cnext = p;
        !           411: 
        !           412:          if (cache->tail == b)
        !           413:            cache->tail = p;
        !           414:        }
        !           415:     }
        !           416:   else
        !           417:     {
        !           418:       /* cache miss; reuse least-used cache bucket */
        !           419: 
        !           420:       ++cache->misses;
        !           421: 
        !           422:       b = cache->tail;
        !           423: 
        !           424:       if (reuse(cache, b, bnum) == -1)
        !           425:        goto fail;
        !           426: 
        !           427:       if (fill)
        !           428:        {
        !           429:          unsigned int len = 0;
        !           430: 
        !           431:          chain[len]   = b;
        !           432:          slots[len++] = hslot;
        !           433: 
        !           434:          for (bptr = b->cprev;
        !           435:               len < (HFS_BLOCKBUFSZ >> 1) && ++bnum < cache->vol->vlen;
        !           436:               bptr = bptr->cprev)
        !           437:            {
        !           438:              if (findbucket(cache, bnum, &hslot))
        !           439:                break;
        !           440: 
        !           441:              if (reuse(cache, bptr, bnum) == -1)
        !           442:                goto fail;
        !           443: 
        !           444:              chain[len]   = bptr;
        !           445:              slots[len++] = hslot;
        !           446:            }
        !           447: 
        !           448:          if (fillbuckets(cache->vol, chain, len) == -1)
        !           449:            goto fail;
        !           450: 
        !           451:          while (--len)
        !           452:            {
        !           453:              cplace(cache, chain[len]);
        !           454:              hplace(slots[len], chain[len]);
        !           455:            }
        !           456: 
        !           457:          hslot = slots[0];
        !           458:        }
        !           459: 
        !           460:       /* move bucket to appropriate place in chain */
        !           461: 
        !           462:       cplace(cache, b);
        !           463:     }
        !           464: 
        !           465:   /* insert at front of hash chain */
        !           466: 
        !           467:   hplace(hslot, b);
        !           468: 
        !           469:   return b;
        !           470: 
        !           471: fail:
        !           472:   return NULL;
        !           473: }
        !           474: 
        !           475: /*
        !           476:  * NAME:       block->readpb()
        !           477:  * DESCRIPTION:        read blocks from the physical medium (bypassing cache)
        !           478:  */
        !           479: int b_readpb(hfsvol *vol, unsigned long bnum, block *bp, unsigned int blen)
        !           480: {
        !           481:   unsigned long nblocks;
        !           482: 
        !           483: # ifdef DEBUG
        !           484:   fprintf(stderr, "BLOCK: READ vol 0x%lx block %lu",
        !           485:          (unsigned long) vol, bnum);
        !           486:   if (blen > 1)
        !           487:     fprintf(stderr, "+%u[..%lu]\n", blen - 1, bnum + blen - 1);
        !           488:   else
        !           489:     fprintf(stderr, "\n");
        !           490: # endif
        !           491: 
        !           492:   nblocks = os_seek(vol->os_fd, bnum, HFS_BLOCKSZ_BITS );
        !           493:   if (nblocks == (unsigned long) -1)
        !           494:     goto fail;
        !           495: 
        !           496:   if (nblocks != bnum)
        !           497:     ERROR(EIO, "block seek failed for read");
        !           498: 
        !           499:   nblocks = os_read(vol->os_fd, bp, blen, HFS_BLOCKSZ_BITS);
        !           500:   if (nblocks == (unsigned long) -1)
        !           501:     goto fail;
        !           502: 
        !           503:   if (nblocks != blen)
        !           504:     ERROR(EIO, "incomplete block read");
        !           505: 
        !           506:   return 0;
        !           507: 
        !           508: fail:
        !           509:   return -1;
        !           510: }
        !           511: 
        !           512: 
        !           513: /*
        !           514:  * NAME:       block->readlb()
        !           515:  * DESCRIPTION:        read a logical block from a volume (or from the cache)
        !           516:  */
        !           517: int b_readlb(hfsvol *vol, unsigned long bnum, block *bp)
        !           518: {
        !           519:   if (vol->vlen > 0 && bnum >= vol->vlen)
        !           520:     ERROR(EIO, "read nonexistent logical block");
        !           521: 
        !           522:   if (vol->cache)
        !           523:     {
        !           524:       bucket *b;
        !           525: 
        !           526:       b = getbucket(vol->cache, bnum, 1);
        !           527:       if (b == NULL)
        !           528:        goto fail;
        !           529: 
        !           530:       memcpy(bp, b->data, HFS_BLOCKSZ);
        !           531:     }
        !           532:   else
        !           533:     {
        !           534:       if (b_readpb(vol, vol->vstart + bnum, bp, 1) == -1)
        !           535:        goto fail;
        !           536:     }
        !           537: 
        !           538:   return 0;
        !           539: 
        !           540: fail:
        !           541:   return -1;
        !           542: }
        !           543: 
        !           544: /*
        !           545:  * NAME:       block->readab()
        !           546:  * DESCRIPTION:        read a block from an allocation block from a volume
        !           547:  */
        !           548: int b_readab(hfsvol *vol, unsigned int anum, unsigned int index, block *bp)
        !           549: {
        !           550:   /* verify the allocation block exists and is marked as in-use */
        !           551: 
        !           552:   if (anum >= vol->mdb.drNmAlBlks)
        !           553:     ERROR(EIO, "read nonexistent allocation block");
        !           554:   else if (vol->vbm && ! BMTST(vol->vbm, anum))
        !           555:     ERROR(EIO, "read unallocated block");
        !           556: 
        !           557:   return b_readlb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + index, bp);
        !           558: 
        !           559: fail:
        !           560:   return -1;
        !           561: }
        !           562: 
        !           563: 
        !           564: /*
        !           565:  * NAME:       block->size()
        !           566:  * DESCRIPTION:        return the number of physical blocks on a volume's medium
        !           567:  */
        !           568: unsigned long b_size(hfsvol *vol)
        !           569: {
        !           570:   unsigned long low, high, mid;
        !           571:   block b;
        !           572: 
        !           573:   high = os_seek(vol->os_fd, -1, HFS_BLOCKSZ_BITS);
        !           574: 
        !           575:   if (high != (unsigned long) -1 && high > 0)
        !           576:     return high;
        !           577: 
        !           578:   /* manual size detection: first check there is at least 1 block in medium */
        !           579: 
        !           580:   if (b_readpb(vol, 0, &b, 1) == -1)
        !           581:     ERROR(EIO, "size of medium indeterminable or empty");
        !           582: 
        !           583:   for (low = 0, high = 2880;
        !           584:        high > 0 && b_readpb(vol, high - 1, &b, 1) != -1;
        !           585:        high <<= 1)
        !           586:     low = high - 1;
        !           587: 
        !           588:   if (high == 0)
        !           589:     ERROR(EIO, "size of medium indeterminable or too large");
        !           590: 
        !           591:   /* common case: 1440K floppy */
        !           592: 
        !           593:   if (low == 2879 && b_readpb(vol, 2880, &b, 1) == -1)
        !           594:     return 2880;
        !           595: 
        !           596:   /* binary search for other sizes */
        !           597: 
        !           598:   while (low < high - 1)
        !           599:     {
        !           600:       mid = (low + high) >> 1;
        !           601: 
        !           602:       if (b_readpb(vol, mid, &b, 1) == -1)
        !           603:        high = mid;
        !           604:       else
        !           605:        low = mid;
        !           606:     }
        !           607: 
        !           608:   return low + 1;
        !           609: 
        !           610: fail:
        !           611:   return 0;
        !           612: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.