Annotation of qemu/roms/openbios/fs/hfs/volume.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: 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.