Annotation of qemu/roms/openbios/fs/hfs/volume.c, revision 1.1.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: volume.c,v 1.12 1998/11/02 22:09:10 rob Exp $
                     21:  */
                     22: 
                     23: #include "config.h"
                     24: #include "libhfs.h"
                     25: #include "volume.h"
                     26: #include "data.h"
                     27: #include "block.h"
                     28: #include "low.h"
                     29: #include "medium.h"
                     30: #include "file.h"
                     31: #include "btree.h"
                     32: #include "record.h"
                     33: #include "os.h"
                     34: 
                     35: #include "libc/byteorder.h"
                     36: 
                     37: /*
                     38:  * NAME:       vol->init()
                     39:  * DESCRIPTION:        initialize volume structure
                     40:  */
                     41: void v_init(hfsvol *vol, int flags)
                     42: {
                     43:   btree *ext = &vol->ext;
                     44:   btree *cat = &vol->cat;
                     45: 
                     46:   vol->os_fd       = 0;
                     47:   vol->flags      = flags & HFS_VOL_OPT_MASK;
                     48: 
                     49:   vol->pnum       = -1;
                     50:   vol->vstart     = 0;
                     51:   vol->vlen       = 0;
                     52:   vol->lpa        = 0;
                     53: 
                     54:   vol->cache      = NULL;
                     55: 
                     56:   vol->vbm        = NULL;
                     57:   vol->vbmsz      = 0;
                     58: 
                     59:   f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow");
                     60: 
                     61:   ext->map        = NULL;
                     62:   ext->mapsz      = 0;
                     63:   ext->flags      = 0;
                     64: 
                     65:   ext->keyunpack  = (keyunpackfunc)  r_unpackextkey;
                     66:   ext->keycompare = (keycomparefunc) r_compareextkeys;
                     67: 
                     68:   f_init(&cat->f, vol, HFS_CNID_CAT, "catalog");
                     69: 
                     70:   cat->map        = NULL;
                     71:   cat->mapsz      = 0;
                     72:   cat->flags      = 0;
                     73: 
                     74:   cat->keyunpack  = (keyunpackfunc)  r_unpackcatkey;
                     75:   cat->keycompare = (keycomparefunc) r_comparecatkeys;
                     76: 
                     77:   vol->cwd        = HFS_CNID_ROOTDIR;
                     78: 
                     79:   vol->refs       = 0;
                     80:   vol->files      = NULL;
                     81:   vol->dirs       = NULL;
                     82: 
                     83:   vol->prev       = NULL;
                     84:   vol->next       = NULL;
                     85: }
                     86: 
                     87: /*
                     88:  * NAME:       vol->open()
                     89:  * DESCRIPTION:        open volume source and lock against concurrent updates
                     90:  */
                     91: int v_open(hfsvol *vol, int os_fd )
                     92: {
                     93:   if (vol->flags & HFS_VOL_OPEN)
                     94:     ERROR(EINVAL, "volume already open");
                     95: 
                     96:   vol->flags |= HFS_VOL_OPEN;
                     97:   vol->os_fd = os_fd;
                     98: 
                     99:   /* initialize volume block cache (OK to fail) */
                    100: 
                    101:   if (! (vol->flags & HFS_OPT_NOCACHE) &&
                    102:       b_init(vol) != -1)
                    103:     vol->flags |= HFS_VOL_USINGCACHE;
                    104: 
                    105:   return 0;
                    106: 
                    107: fail:
                    108:   return -1;
                    109: }
                    110: 
                    111: /*
                    112:  * NAME:       vol->close()
                    113:  * DESCRIPTION:        close access path to volume source
                    114:  */
                    115: int v_close(hfsvol *vol)
                    116: {
                    117:   int result = 0;
                    118: 
                    119:   if (! (vol->flags & HFS_VOL_OPEN))
                    120:     goto done;
                    121: 
                    122:   if ((vol->flags & HFS_VOL_USINGCACHE) &&
                    123:       b_finish(vol) == -1)
                    124:     result = -1;
                    125: 
                    126:   vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE);
                    127: 
                    128:   /* free dynamically allocated structures */
                    129: 
                    130:   FREE(vol->vbm);
                    131: 
                    132:   vol->vbm   = NULL;
                    133:   vol->vbmsz = 0;
                    134: 
                    135:   FREE(vol->ext.map);
                    136:   FREE(vol->cat.map);
                    137: 
                    138:   vol->ext.map = NULL;
                    139:   vol->cat.map = NULL;
                    140: 
                    141: done:
                    142:   return result;
                    143: }
                    144: 
                    145: /*
                    146:  * NAME:       vol->same()
                    147:  * DESCRIPTION:        return 1 iff path is same as open volume
                    148:  */
                    149: int v_same(hfsvol *vol, int os_fd )
                    150: {
                    151:   return vol->os_fd == os_fd;
                    152: }
                    153: 
                    154: /*
                    155:  * NAME:       vol->geometry()
                    156:  * DESCRIPTION:        determine volume location and size (possibly in a partition)
                    157:  */
                    158: int v_geometry(hfsvol *vol, int pnum)
                    159: {
                    160:   Partition map;
                    161:   unsigned long bnum = 0;
                    162:   int found;
                    163: 
                    164:   vol->pnum = pnum;
                    165: 
                    166:   if (pnum == 0)
                    167:     {
                    168:       vol->vstart = 0;
                    169:       vol->vlen   = b_size(vol);
                    170: 
                    171:       if (vol->vlen == 0)
                    172:        goto fail;
                    173:     }
                    174:   else
                    175:     {
                    176:       while (pnum--)
                    177:        {
                    178:          found = m_findpmentry(vol, "Apple_HFS", &map, &bnum);
                    179:          if (found == -1 || ! found)
                    180:            goto fail;
                    181:        }
                    182: 
                    183:       vol->vstart = map.pmPyPartStart;
                    184:       vol->vlen   = map.pmPartBlkCnt;
                    185: 
                    186:       if (map.pmDataCnt)
                    187:        {
                    188:          if ((unsigned long) map.pmLgDataStart +
                    189:              (unsigned long) map.pmDataCnt > vol->vlen)
                    190:            ERROR(EINVAL, "partition data overflows partition");
                    191: 
                    192:          vol->vstart += (unsigned long) map.pmLgDataStart;
                    193:          vol->vlen    = map.pmDataCnt;
                    194:        }
                    195: 
                    196:       if (vol->vlen == 0)
                    197:        ERROR(EINVAL, "volume partition is empty");
                    198:     }
                    199: 
                    200:   if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS))
                    201:     ERROR(EINVAL, "volume is smaller than 800K");
                    202: 
                    203:   return 0;
                    204: 
                    205: fail:
                    206:   return -1;
                    207: }
                    208: 
                    209: /*
                    210:  * NAME:       vol->readmdb()
                    211:  * DESCRIPTION:        load Master Directory Block into memory
                    212:  */
                    213: int v_readmdb(hfsvol *vol)
                    214: {
                    215:   if (l_getmdb(vol, &vol->mdb, 0) == -1)
                    216:     goto fail;
                    217: 
                    218:   if (vol->mdb.drSigWord != HFS_SIGWORD)
                    219:     {
                    220:       if (vol->mdb.drSigWord == HFS_SIGWORD_MFS)
                    221:        ERROR(EINVAL, "MFS volume format not supported");
                    222:       else
                    223:        ERROR(EINVAL, "not a Macintosh HFS volume");
                    224:     }
                    225: 
                    226:   if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
                    227:     ERROR(EINVAL, "bad volume allocation block size");
                    228: 
                    229:   vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS;
                    230: 
                    231:   /* extents pseudo-file structs */
                    232: 
                    233:   vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN;
                    234:   vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize;
                    235:   vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize;
                    236: 
                    237:   vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
                    238:   vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
                    239: 
                    240:   memcpy(&vol->ext.f.cat.u.fil.filExtRec,
                    241:         &vol->mdb.drXTExtRec, sizeof(ExtDataRec));
                    242: 
                    243:   f_selectfork(&vol->ext.f, fkData);
                    244: 
                    245:   /* catalog pseudo-file structs */
                    246: 
                    247:   vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN;
                    248:   vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize;
                    249:   vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize;
                    250: 
                    251:   vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
                    252:   vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
                    253: 
                    254:   memcpy(&vol->cat.f.cat.u.fil.filExtRec,
                    255:         &vol->mdb.drCTExtRec, sizeof(ExtDataRec));
                    256: 
                    257:   f_selectfork(&vol->cat.f, fkData);
                    258: 
                    259:   return 0;
                    260: 
                    261: fail:
                    262:   return -1;
                    263: }
                    264: 
                    265: /*
                    266:  * NAME:       vol->readvbm()
                    267:  * DESCRIPTION:        read volume bitmap into memory
                    268:  */
                    269: int v_readvbm(hfsvol *vol)
                    270: {
                    271:   unsigned int vbmst = vol->mdb.drVBMSt;
                    272:   unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12;
                    273:   block *bp;
                    274: 
                    275:   ASSERT(vol->vbm == 0);
                    276: 
                    277:   if (vol->mdb.drAlBlSt - vbmst < vbmsz)
                    278:     ERROR(EIO, "volume bitmap collides with volume data");
                    279: 
                    280:   vol->vbm = ALLOC(block, vbmsz);
                    281:   if (vol->vbm == NULL)
                    282:     ERROR(ENOMEM, NULL);
                    283: 
                    284:   vol->vbmsz = vbmsz;
                    285: 
                    286:   for (bp = vol->vbm; vbmsz--; ++bp)
                    287:     {
                    288:       if (b_readlb(vol, vbmst++, bp) == -1)
                    289:        goto fail;
                    290:     }
                    291: 
                    292:   return 0;
                    293: 
                    294: fail:
                    295:   FREE(vol->vbm);
                    296: 
                    297:   vol->vbm   = NULL;
                    298:   vol->vbmsz = 0;
                    299: 
                    300:   return -1;
                    301: }
                    302: 
                    303: /*
                    304:  * NAME:       vol->mount()
                    305:  * DESCRIPTION:        load volume information into memory
                    306:  */
                    307: int v_mount(hfsvol *vol)
                    308: {
                    309:   /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */
                    310: 
                    311:   if (v_readmdb(vol) == -1 ||
                    312:       v_readvbm(vol) == -1 ||
                    313:       bt_readhdr(&vol->ext) == -1 ||
                    314:       bt_readhdr(&vol->cat) == -1)
                    315:     goto fail;
                    316: 
                    317:   if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED)
                    318:     vol->flags |= HFS_VOL_READONLY;
                    319:   else if (vol->flags & HFS_VOL_READONLY)
                    320:     vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
                    321:   else
                    322:     vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
                    323: 
                    324:   vol->flags |= HFS_VOL_MOUNTED;
                    325: 
                    326:   return 0;
                    327: 
                    328: fail:
                    329:   return -1;
                    330: }
                    331: 
                    332: /*
                    333:  * NAME:       vol->catsearch()
                    334:  * DESCRIPTION:        search catalog tree
                    335:  */
                    336: int v_catsearch(hfsvol *vol, unsigned long parid, const char *name,
                    337:                CatDataRec *data, char *cname, node *np)
                    338: {
                    339:   CatKeyRec key;
                    340:   byte pkey[HFS_CATKEYLEN];
                    341:   const byte *ptr;
                    342:   node n;
                    343:   int found;
                    344: 
                    345:   if (np == NULL)
                    346:     np = &n;
                    347: 
                    348:   r_makecatkey(&key, parid, name);
                    349:   r_packcatkey(&key, pkey, NULL);
                    350: 
                    351:   found = bt_search(&vol->cat, pkey, np);
                    352:   if (found <= 0)
                    353:     return found;
                    354: 
                    355:   ptr = HFS_NODEREC(*np, np->rnum);
                    356: 
                    357:   if (cname)
                    358:     {
                    359:       r_unpackcatkey(ptr, &key);
                    360:       strcpy(cname, key.ckrCName);
                    361:     }
                    362: 
                    363:   if (data)
                    364:     r_unpackcatdata(HFS_RECDATA(ptr), data);
                    365: 
                    366:   return 1;
                    367: }
                    368: 
                    369: /*
                    370:  * NAME:       vol->extsearch()
                    371:  * DESCRIPTION:        search extents tree
                    372:  */
                    373: int v_extsearch(hfsfile *file, unsigned int fabn,
                    374:                ExtDataRec *data, node *np)
                    375: {
                    376:   ExtKeyRec key;
                    377:   ExtDataRec extsave;
                    378:   unsigned int fabnsave;
                    379:   byte pkey[HFS_EXTKEYLEN];
                    380:   const byte *ptr;
                    381:   node n;
                    382:   int found;
                    383: 
                    384:   if (np == NULL)
                    385:     np = &n;
                    386: 
                    387:   r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn);
                    388:   r_packextkey(&key, pkey, NULL);
                    389: 
                    390:   /* in case bt_search() clobbers these */
                    391: 
                    392:   memcpy(&extsave, &file->ext, sizeof(ExtDataRec));
                    393:   fabnsave = file->fabn;
                    394: 
                    395:   found = bt_search(&file->vol->ext, pkey, np);
                    396: 
                    397:   memcpy(&file->ext, &extsave, sizeof(ExtDataRec));
                    398:   file->fabn = fabnsave;
                    399: 
                    400:   if (found <= 0)
                    401:     return found;
                    402: 
                    403:   if (data)
                    404:     {
                    405:       ptr = HFS_NODEREC(*np, np->rnum);
                    406:       r_unpackextdata(HFS_RECDATA(ptr), data);
                    407:     }
                    408: 
                    409:   return 1;
                    410: }
                    411: 
                    412: /*
                    413:  * NAME:       vol->getthread()
                    414:  * DESCRIPTION:        retrieve catalog thread information for a file or directory
                    415:  */
                    416: int v_getthread(hfsvol *vol, unsigned long id,
                    417:                CatDataRec *thread, node *np, int type)
                    418: {
                    419:   CatDataRec rec;
                    420:   int found;
                    421: 
                    422:   if (thread == NULL)
                    423:     thread = &rec;
                    424: 
                    425:   found = v_catsearch(vol, id, "", thread, NULL, np);
                    426:   if (found == 1 && thread->cdrType != type)
                    427:     ERROR(EIO, "bad thread record");
                    428: 
                    429:   return found;
                    430: 
                    431: fail:
                    432:   return -1;
                    433: }
                    434: 
                    435: 
                    436: /*
                    437:  * NAME:       vol->resolve()
                    438:  * DESCRIPTION:        translate a pathname; return catalog information
                    439:  */
                    440: int v_resolve(hfsvol **vol, const char *path,
                    441:               CatDataRec *data, unsigned long *parid, char *fname, node *np)
                    442: {
                    443:   unsigned long dirid;
                    444:   char name[HFS_MAX_FLEN + 1], *nptr;
                    445:   int found = 0;
                    446: 
                    447:   if (*path == 0)
                    448:     ERROR(ENOENT, "empty path");
                    449: 
                    450:   if (parid)
                    451:     *parid = 0;
                    452: 
                    453:   nptr = strchr(path, ':');
                    454: 
                    455:   if (*path == ':' || nptr == NULL)
                    456:     {
                    457:       dirid = (*vol)->cwd;  /* relative path */
                    458: 
                    459:       if (*path == ':')
                    460:        ++path;
                    461: 
                    462:       if (*path == 0)
                    463:        {
                    464:           found = v_getdthread(*vol, dirid, data, NULL);
                    465:          if (found == -1)
                    466:            goto fail;
                    467: 
                    468:          if (found)
                    469:            {
                    470:              if (parid)
                    471:                *parid = data->u.dthd.thdParID;
                    472: 
                    473:              found = v_catsearch(*vol, data->u.dthd.thdParID,
                    474:                                  data->u.dthd.thdCName, data, fname, np);
                    475:              if (found == -1)
                    476:                goto fail;
                    477:            }
                    478: 
                    479:          goto done;
                    480:        }
                    481:     }
                    482:   else
                    483:     {
                    484:       hfsvol *check;
                    485: 
                    486:       dirid = HFS_CNID_ROOTPAR;  /* absolute path */
                    487: 
                    488:       if (nptr - path > HFS_MAX_VLEN)
                    489:         ERROR(ENAMETOOLONG, NULL);
                    490: 
                    491:       strncpy(name, path, nptr - path);
                    492:       name[nptr - path] = 0;
                    493: 
                    494:       for (check = hfs_mounts; check; check = check->next)
                    495:        {
                    496:          if (d_relstring(check->mdb.drVN, name) == 0)
                    497:            {
                    498:              *vol = check;
                    499:              break;
                    500:            }
                    501:        }
                    502:     }
                    503: 
                    504:   while (1)
                    505:     {
                    506:       while (*path == ':')
                    507:        {
                    508:          ++path;
                    509: 
                    510:           found = v_getdthread(*vol, dirid, data, NULL);
                    511:          if (found == -1)
                    512:            goto fail;
                    513:          else if (! found)
                    514:            goto done;
                    515: 
                    516:          dirid = data->u.dthd.thdParID;
                    517:        }
                    518: 
                    519:       if (*path == 0)
                    520:        {
                    521:           found = v_getdthread(*vol, dirid, data, NULL);
                    522:          if (found == -1)
                    523:            goto fail;
                    524: 
                    525:          if (found)
                    526:            {
                    527:              if (parid)
                    528:                *parid = data->u.dthd.thdParID;
                    529: 
                    530:              found = v_catsearch(*vol, data->u.dthd.thdParID,
                    531:                                  data->u.dthd.thdCName, data, fname, np);
                    532:              if (found == -1)
                    533:                goto fail;
                    534:            }
                    535: 
                    536:          goto done;
                    537:        }
                    538: 
                    539:       nptr = name;
                    540:       while (nptr < name + sizeof(name) - 1 && *path && *path != ':')
                    541:        *nptr++ = *path++;
                    542: 
                    543:       if (*path && *path != ':')
                    544:         ERROR(ENAMETOOLONG, NULL);
                    545: 
                    546:       *nptr = 0;
                    547:       if (*path == ':')
                    548:        ++path;
                    549: 
                    550:       if (parid)
                    551:        *parid = dirid;
                    552: 
                    553:       found = v_catsearch(*vol, dirid, name, data, fname, np);
                    554:       if (found == -1)
                    555:        goto fail;
                    556: 
                    557:       if (! found)
                    558:        {
                    559:          if (*path && parid)
                    560:            *parid = 0;
                    561: 
                    562:          if (*path == 0 && fname)
                    563:            strcpy(fname, name);
                    564: 
                    565:          goto done;
                    566:        }
                    567: 
                    568:       switch (data->cdrType)
                    569:        {
                    570:        case cdrDirRec:
                    571:          if (*path == 0)
                    572:            goto done;
                    573: 
                    574:          dirid = data->u.dir.dirDirID;
                    575:          break;
                    576: 
                    577:        case cdrFilRec:
                    578:          if (*path == 0)
                    579:            goto done;
                    580: 
                    581:          ERROR(ENOTDIR, "invalid pathname");
                    582: 
                    583:        default:
                    584:          ERROR(EIO, "unexpected catalog record");
                    585:        }
                    586:     }
                    587: 
                    588: done:
                    589:   return found;
                    590: 
                    591: fail:
                    592:   return -1;
                    593: }
                    594: 
                    595: /* Determine whether the volume is a HFS volume */
                    596: int
                    597: v_probe(int fd, long long offset)
                    598: {
                    599:        MDB *mdb;
                    600: 
                    601:        mdb = (MDB*)malloc(2 * 512);
                    602:        os_seek_offset( fd, 2 * 512 + offset );
                    603:        os_read(fd, mdb, 2, 9);
                    604: 
                    605:        if (__be16_to_cpu(mdb->drSigWord) != HFS_SIGWORD) {
                    606:                free(mdb);
                    607:                return 0;
                    608:        }
                    609: 
                    610:        free(mdb);
                    611:        return -1;
                    612: }

unix.superglobalmegacorp.com

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