Annotation of qemu/roms/openbios/fs/hfs/hfs.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: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $
                     21:  */
                     22: 
                     23: #include "config.h"
                     24: #include "libhfs.h"
                     25: #include "data.h"
                     26: #include "block.h"
                     27: #include "medium.h"
                     28: #include "file.h"
                     29: #include "btree.h"
                     30: #include "node.h"
                     31: #include "record.h"
                     32: #include "volume.h"
                     33: 
                     34: const char *hfs_error = "no error";    /* static error string */
                     35: 
                     36: hfsvol *hfs_mounts;                    /* linked list of mounted volumes */
                     37: 
                     38: static
                     39: hfsvol *curvol;                                /* current volume */
                     40: 
                     41: 
                     42: /*
                     43:  * NAME:       getvol()
                     44:  * DESCRIPTION:        validate a volume reference
                     45:  */
                     46: static
                     47: int getvol(hfsvol **vol)
                     48: {
                     49:   if (*vol == NULL)
                     50:     {
                     51:       if (curvol == NULL)
                     52:        ERROR(EINVAL, "no volume is current");
                     53: 
                     54:       *vol = curvol;
                     55:     }
                     56: 
                     57:   return 0;
                     58: 
                     59: fail:
                     60:   return -1;
                     61: }
                     62: 
                     63: /* High-Level Volume Routines ============================================== */
                     64: 
                     65: /*
                     66:  * NAME:       hfs->mount()
                     67:  * DESCRIPTION:        open an HFS volume; return volume descriptor or 0 (error)
                     68:  */
                     69: hfsvol *hfs_mount( int os_fd, int pnum)
                     70: {
                     71:   hfsvol *vol, *check;
                     72:   int mode = HFS_MODE_RDONLY;
                     73: 
                     74:   /* see if the volume is already mounted */
                     75:   for (check = hfs_mounts; check; check = check->next)
                     76:     {
                     77:       if (check->pnum == pnum && v_same(check, os_fd) == 1)
                     78:        {
                     79:            vol = check;
                     80:            goto done;
                     81:        }
                     82:     }
                     83: 
                     84:   vol = ALLOC(hfsvol, 1);
                     85:   if (vol == NULL)
                     86:     ERROR(ENOMEM, NULL);
                     87: 
                     88:   v_init(vol, mode);
                     89: 
                     90:   vol->flags |= HFS_VOL_READONLY;
                     91:   if( v_open(vol, os_fd) == -1 )
                     92:          goto fail;
                     93: 
                     94:   /* mount the volume */
                     95: 
                     96:   if (v_geometry(vol, pnum) == -1 ||
                     97:       v_mount(vol) == -1)
                     98:     goto fail;
                     99: 
                    100:   /* add to linked list of volumes */
                    101: 
                    102:   vol->prev = NULL;
                    103:   vol->next = hfs_mounts;
                    104: 
                    105:   if (hfs_mounts)
                    106:     hfs_mounts->prev = vol;
                    107: 
                    108:   hfs_mounts = vol;
                    109: 
                    110: done:
                    111:   ++vol->refs;
                    112:   curvol = vol;
                    113: 
                    114:   return vol;
                    115: 
                    116: fail:
                    117:   if (vol)
                    118:     {
                    119:       v_close(vol);
                    120:       FREE(vol);
                    121:     }
                    122: 
                    123:   return NULL;
                    124: }
                    125: 
                    126: 
                    127: /*
                    128:  * NAME:       hfs->umount()
                    129:  * DESCRIPTION:        close an HFS volume
                    130:  */
                    131: int hfs_umount(hfsvol *vol)
                    132: {
                    133:   int result = 0;
                    134: 
                    135:   if (getvol(&vol) == -1)
                    136:     goto fail;
                    137: 
                    138:   if (--vol->refs)
                    139:     {
                    140:       goto done;
                    141:     }
                    142: 
                    143:   /* close all open files and directories */
                    144: 
                    145:   while (vol->files)
                    146:     {
                    147:       if (hfs_close(vol->files) == -1)
                    148:        result = -1;
                    149:     }
                    150: 
                    151:   while (vol->dirs)
                    152:     {
                    153:       if (hfs_closedir(vol->dirs) == -1)
                    154:        result = -1;
                    155:     }
                    156: 
                    157:   /* close medium */
                    158: 
                    159:   if (v_close(vol) == -1)
                    160:     result = -1;
                    161: 
                    162:   /* remove from linked list of volumes */
                    163: 
                    164:   if (vol->prev)
                    165:     vol->prev->next = vol->next;
                    166:   if (vol->next)
                    167:     vol->next->prev = vol->prev;
                    168: 
                    169:   if (vol == hfs_mounts)
                    170:     hfs_mounts = vol->next;
                    171:   if (vol == curvol)
                    172:     curvol = NULL;
                    173: 
                    174:   FREE(vol);
                    175: 
                    176: done:
                    177:   return result;
                    178: 
                    179: fail:
                    180:   return -1;
                    181: }
                    182: 
                    183: /*
                    184:  * NAME:       hfs->umountall()
                    185:  * DESCRIPTION:        unmount all mounted volumes
                    186:  */
                    187: void hfs_umountall(void)
                    188: {
                    189:   while (hfs_mounts)
                    190:     hfs_umount(hfs_mounts);
                    191: }
                    192: 
                    193: /*
                    194:  * NAME:       hfs->getvol()
                    195:  * DESCRIPTION:        return a pointer to a mounted volume
                    196:  */
                    197: hfsvol *hfs_getvol(const char *name)
                    198: {
                    199:   hfsvol *vol;
                    200: 
                    201:   if (name == NULL)
                    202:     return curvol;
                    203: 
                    204:   for (vol = hfs_mounts; vol; vol = vol->next)
                    205:     {
                    206:       if (d_relstring(name, vol->mdb.drVN) == 0)
                    207:        return vol;
                    208:     }
                    209: 
                    210:   return NULL;
                    211: }
                    212: 
                    213: /*
                    214:  * NAME:       hfs->setvol()
                    215:  * DESCRIPTION:        change the current volume
                    216:  */
                    217: void hfs_setvol(hfsvol *vol)
                    218: {
                    219:   curvol = vol;
                    220: }
                    221: 
                    222: /*
                    223:  * NAME:       hfs->vstat()
                    224:  * DESCRIPTION:        return volume statistics
                    225:  */
                    226: int hfs_vstat(hfsvol *vol, hfsvolent *ent)
                    227: {
                    228:   if (getvol(&vol) == -1)
                    229:     goto fail;
                    230: 
                    231:   strcpy(ent->name, vol->mdb.drVN);
                    232: 
                    233:   ent->flags     = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0;
                    234: 
                    235:   ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
                    236:   ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz;
                    237: 
                    238:   ent->alblocksz = vol->mdb.drAlBlkSiz;
                    239:   ent->clumpsz   = vol->mdb.drClpSiz;
                    240: 
                    241:   ent->numfiles  = vol->mdb.drFilCnt;
                    242:   ent->numdirs   = vol->mdb.drDirCnt;
                    243: 
                    244:   ent->crdate    = d_ltime(vol->mdb.drCrDate);
                    245:   ent->mddate    = d_ltime(vol->mdb.drLsMod);
                    246:   ent->bkdate    = d_ltime(vol->mdb.drVolBkUp);
                    247: 
                    248:   ent->blessed   = vol->mdb.drFndrInfo[0];
                    249: 
                    250:   return 0;
                    251: 
                    252: fail:
                    253:   return -1;
                    254: }
                    255: 
                    256: 
                    257: /* High-Level Directory Routines =========================================== */
                    258: 
                    259: /*
                    260:  * NAME:       hfs->chdir()
                    261:  * DESCRIPTION:        change current HFS directory
                    262:  */
                    263: int hfs_chdir(hfsvol *vol, const char *path)
                    264: {
                    265:   CatDataRec data;
                    266: 
                    267:   if (getvol(&vol) == -1 ||
                    268:       v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
                    269:     goto fail;
                    270: 
                    271:   if (data.cdrType != cdrDirRec)
                    272:     ERROR(ENOTDIR, NULL);
                    273: 
                    274:   vol->cwd = data.u.dir.dirDirID;
                    275: 
                    276:   return 0;
                    277: 
                    278: fail:
                    279:   return -1;
                    280: }
                    281: 
                    282: /*
                    283:  * NAME:       hfs->getcwd()
                    284:  * DESCRIPTION:        return the current working directory ID
                    285:  */
                    286: unsigned long hfs_getcwd(hfsvol *vol)
                    287: {
                    288:   if (getvol(&vol) == -1)
                    289:     return 0;
                    290: 
                    291:   return vol->cwd;
                    292: }
                    293: 
                    294: /*
                    295:  * NAME:       hfs->setcwd()
                    296:  * DESCRIPTION:        set the current working directory ID
                    297:  */
                    298: int hfs_setcwd(hfsvol *vol, unsigned long id)
                    299: {
                    300:   if (getvol(&vol) == -1)
                    301:     goto fail;
                    302: 
                    303:   if (id == vol->cwd)
                    304:     goto done;
                    305: 
                    306:   /* make sure the directory exists */
                    307: 
                    308:   if (v_getdthread(vol, id, NULL, NULL) <= 0)
                    309:     goto fail;
                    310: 
                    311:   vol->cwd = id;
                    312: 
                    313: done:
                    314:   return 0;
                    315: 
                    316: fail:
                    317:   return -1;
                    318: }
                    319: 
                    320: /*
                    321:  * NAME:       hfs->dirinfo()
                    322:  * DESCRIPTION:        given a directory ID, return its (name and) parent ID
                    323:  */
                    324: int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name)
                    325: {
                    326:   CatDataRec thread;
                    327: 
                    328:   if (getvol(&vol) == -1 ||
                    329:       v_getdthread(vol, *id, &thread, NULL) <= 0)
                    330:     goto fail;
                    331: 
                    332:   *id = thread.u.dthd.thdParID;
                    333: 
                    334:   if (name)
                    335:     strcpy(name, thread.u.dthd.thdCName);
                    336: 
                    337:   return 0;
                    338: 
                    339: fail:
                    340:   return -1;
                    341: }
                    342: 
                    343: /*
                    344:  * NAME:       hfs->opendir()
                    345:  * DESCRIPTION:        prepare to read the contents of a directory
                    346:  */
                    347: hfsdir *hfs_opendir(hfsvol *vol, const char *path)
                    348: {
                    349:   hfsdir *dir = NULL;
                    350:   CatKeyRec key;
                    351:   CatDataRec data;
                    352:   byte pkey[HFS_CATKEYLEN];
                    353: 
                    354:   if (getvol(&vol) == -1)
                    355:     goto fail;
                    356: 
                    357:   dir = ALLOC(hfsdir, 1);
                    358:   if (dir == NULL)
                    359:     ERROR(ENOMEM, NULL);
                    360: 
                    361:   dir->vol = vol;
                    362: 
                    363:   if (*path == 0)
                    364:     {
                    365:       /* meta-directory containing root dirs from all mounted volumes */
                    366: 
                    367:       dir->dirid = 0;
                    368:       dir->vptr  = hfs_mounts;
                    369:     }
                    370:   else
                    371:     {
                    372:       if (v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
                    373:        goto fail;
                    374: 
                    375:       if (data.cdrType != cdrDirRec)
                    376:         ERROR(ENOTDIR, NULL);
                    377: 
                    378:       dir->dirid = data.u.dir.dirDirID;
                    379:       dir->vptr  = NULL;
                    380: 
                    381:       r_makecatkey(&key, dir->dirid, "");
                    382:       r_packcatkey(&key, pkey, NULL);
                    383: 
                    384:       if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
                    385:        goto fail;
                    386:     }
                    387: 
                    388:   dir->prev = NULL;
                    389:   dir->next = vol->dirs;
                    390: 
                    391:   if (vol->dirs)
                    392:     vol->dirs->prev = dir;
                    393: 
                    394:   vol->dirs = dir;
                    395: 
                    396:   return dir;
                    397: 
                    398: fail:
                    399:   FREE(dir);
                    400:   return NULL;
                    401: }
                    402: 
                    403: /*
                    404:  * NAME:       hfs->readdir()
                    405:  * DESCRIPTION:        return the next entry in the directory
                    406:  */
                    407: int hfs_readdir(hfsdir *dir, hfsdirent *ent)
                    408: {
                    409:   CatKeyRec key;
                    410:   CatDataRec data;
                    411:   const byte *ptr;
                    412: 
                    413:   if (dir->dirid == 0)
                    414:     {
                    415:       hfsvol *vol;
                    416:       char cname[HFS_MAX_FLEN + 1];
                    417: 
                    418:       for (vol = hfs_mounts; vol; vol = vol->next)
                    419:        {
                    420:          if (vol == dir->vptr)
                    421:            break;
                    422:        }
                    423: 
                    424:       if (vol == NULL)
                    425:        ERROR(ENOENT, "no more entries");
                    426: 
                    427:       if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, NULL) <= 0 ||
                    428:          v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
                    429:                       &data, cname, NULL) <= 0)
                    430:        goto fail;
                    431: 
                    432:       r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
                    433: 
                    434:       dir->vptr = vol->next;
                    435: 
                    436:       goto done;
                    437:     }
                    438: 
                    439:   if (dir->n.rnum == -1)
                    440:     ERROR(ENOENT, "no more entries");
                    441: 
                    442:   while (1)
                    443:     {
                    444:       ++dir->n.rnum;
                    445: 
                    446:       while (dir->n.rnum >= dir->n.nd.ndNRecs)
                    447:        {
                    448:          if (dir->n.nd.ndFLink == 0)
                    449:            {
                    450:              dir->n.rnum = -1;
                    451:              ERROR(ENOENT, "no more entries");
                    452:            }
                    453: 
                    454:          if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1)
                    455:            {
                    456:              dir->n.rnum = -1;
                    457:              goto fail;
                    458:            }
                    459: 
                    460:          dir->n.rnum = 0;
                    461:        }
                    462: 
                    463:       ptr = HFS_NODEREC(dir->n, dir->n.rnum);
                    464: 
                    465:       r_unpackcatkey(ptr, &key);
                    466: 
                    467:       if (key.ckrParID != dir->dirid)
                    468:        {
                    469:          dir->n.rnum = -1;
                    470:          ERROR(ENOENT, "no more entries");
                    471:        }
                    472: 
                    473:       r_unpackcatdata(HFS_RECDATA(ptr), &data);
                    474: 
                    475:       switch (data.cdrType)
                    476:        {
                    477:        case cdrDirRec:
                    478:        case cdrFilRec:
                    479:          r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
                    480:          goto done;
                    481: 
                    482:        case cdrThdRec:
                    483:        case cdrFThdRec:
                    484:          break;
                    485: 
                    486:        default:
                    487:          dir->n.rnum = -1;
                    488:          ERROR(EIO, "unexpected directory entry found");
                    489:        }
                    490:     }
                    491: 
                    492: done:
                    493:   return 0;
                    494: 
                    495: fail:
                    496:   return -1;
                    497: }
                    498: 
                    499: /*
                    500:  * NAME:       hfs->closedir()
                    501:  * DESCRIPTION:        stop reading a directory
                    502:  */
                    503: int hfs_closedir(hfsdir *dir)
                    504: {
                    505:   hfsvol *vol = dir->vol;
                    506: 
                    507:   if (dir->prev)
                    508:     dir->prev->next = dir->next;
                    509:   if (dir->next)
                    510:     dir->next->prev = dir->prev;
                    511:   if (dir == vol->dirs)
                    512:     vol->dirs = dir->next;
                    513: 
                    514:   FREE(dir);
                    515: 
                    516:   return 0;
                    517: }
                    518: 
                    519: /* High-Level File Routines ================================================ */
                    520: 
                    521: /*
                    522:  * NAME:       hfs->open()
                    523:  * DESCRIPTION:        prepare a file for I/O
                    524:  */
                    525: hfsfile *hfs_open(hfsvol *vol, const char *path)
                    526: {
                    527:   hfsfile *file = NULL;
                    528: 
                    529:   if (getvol(&vol) == -1)
                    530:     goto fail;
                    531: 
                    532:   file = ALLOC(hfsfile, 1);
                    533:   if (file == NULL)
                    534:     ERROR(ENOMEM, NULL);
                    535: 
                    536:   if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, NULL) <= 0)
                    537:     goto fail;
                    538: 
                    539:   if (file->cat.cdrType != cdrFilRec)
                    540:     ERROR(EISDIR, NULL);
                    541: 
                    542:   /* package file handle for user */
                    543: 
                    544:   file->vol   = vol;
                    545:   file->flags = 0;
                    546: 
                    547:   f_selectfork(file, fkData);
                    548: 
                    549:   file->prev = NULL;
                    550:   file->next = vol->files;
                    551: 
                    552:   if (vol->files)
                    553:     vol->files->prev = file;
                    554: 
                    555:   vol->files = file;
                    556: 
                    557:   return file;
                    558: 
                    559: fail:
                    560:   FREE(file);
                    561:   return NULL;
                    562: }
                    563: 
                    564: /*
                    565:  * NAME:       hfs->setfork()
                    566:  * DESCRIPTION:        select file fork for I/O operations
                    567:  */
                    568: int hfs_setfork(hfsfile *file, int fork)
                    569: {
                    570:   int result = 0;
                    571: 
                    572:   f_selectfork(file, fork ? fkRsrc : fkData);
                    573: 
                    574:   return result;
                    575: }
                    576: 
                    577: /*
                    578:  * NAME:       hfs->getfork()
                    579:  * DESCRIPTION:        return the current fork for I/O operations
                    580:  */
                    581: int hfs_getfork(hfsfile *file)
                    582: {
                    583:   return file->fork != fkData;
                    584: }
                    585: 
                    586: /*
                    587:  * NAME:       hfs->read()
                    588:  * DESCRIPTION:        read from an open file
                    589:  */
                    590: unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len)
                    591: {
                    592:   unsigned long *lglen, count;
                    593:   byte *ptr = buf;
                    594: 
                    595:   f_getptrs(file, NULL, &lglen, NULL);
                    596: 
                    597:   if (file->pos + len > *lglen)
                    598:     len = *lglen - file->pos;
                    599: 
                    600:   count = len;
                    601:   while (count)
                    602:     {
                    603:       unsigned long bnum, offs, chunk;
                    604: 
                    605:       bnum  = file->pos >> HFS_BLOCKSZ_BITS;
                    606:       offs  = file->pos & (HFS_BLOCKSZ - 1);
                    607: 
                    608:       chunk = HFS_BLOCKSZ - offs;
                    609:       if (chunk > count)
                    610:        chunk = count;
                    611: 
                    612:       if (offs == 0 && chunk == HFS_BLOCKSZ)
                    613:        {
                    614:          if (f_getblock(file, bnum, (block *) ptr) == -1)
                    615:            goto fail;
                    616:        }
                    617:       else
                    618:        {
                    619:          block b;
                    620: 
                    621:          if (f_getblock(file, bnum, &b) == -1)
                    622:            goto fail;
                    623: 
                    624:          memcpy(ptr, b + offs, chunk);
                    625:        }
                    626: 
                    627:       ptr += chunk;
                    628: 
                    629:       file->pos += chunk;
                    630:       count     -= chunk;
                    631:     }
                    632: 
                    633:   return len;
                    634: 
                    635: fail:
                    636:   return -1;
                    637: }
                    638: 
                    639: /*
                    640:  * NAME:       hfs->seek()
                    641:  * DESCRIPTION:        change file seek pointer
                    642:  */
                    643: unsigned long hfs_seek(hfsfile *file, long offset, int from)
                    644: {
                    645:   unsigned long *lglen, newpos;
                    646: 
                    647:   f_getptrs(file, NULL, &lglen, NULL);
                    648: 
                    649:   switch (from)
                    650:     {
                    651:     case HFS_SEEK_SET:
                    652:       newpos = (offset < 0) ? 0 : offset;
                    653:       break;
                    654: 
                    655:     case HFS_SEEK_CUR:
                    656:       if (offset < 0 && (unsigned long) -offset > file->pos)
                    657:        newpos = 0;
                    658:       else
                    659:        newpos = file->pos + offset;
                    660:       break;
                    661: 
                    662:     case HFS_SEEK_END:
                    663:       if (offset < 0 && (unsigned long) -offset > *lglen)
                    664:        newpos = 0;
                    665:       else
                    666:        newpos = *lglen + offset;
                    667:       break;
                    668: 
                    669:     default:
                    670:       ERROR(EINVAL, NULL);
                    671:     }
                    672: 
                    673:   if (newpos > *lglen)
                    674:     newpos = *lglen;
                    675: 
                    676:   file->pos = newpos;
                    677: 
                    678:   return newpos;
                    679: 
                    680: fail:
                    681:   return -1;
                    682: }
                    683: 
                    684: /*
                    685:  * NAME:       hfs->close()
                    686:  * DESCRIPTION:        close a file
                    687:  */
                    688: int hfs_close(hfsfile *file)
                    689: {
                    690:   hfsvol *vol = file->vol;
                    691:   int result = 0;
                    692: 
                    693:   if (file->prev)
                    694:     file->prev->next = file->next;
                    695:   if (file->next)
                    696:     file->next->prev = file->prev;
                    697:   if (file == vol->files)
                    698:     vol->files = file->next;
                    699: 
                    700:   FREE(file);
                    701: 
                    702:   return result;
                    703: }
                    704: 
                    705: /* High-Level Catalog Routines ============================================= */
                    706: 
                    707: /*
                    708:  * NAME:       hfs->stat()
                    709:  * DESCRIPTION:        return catalog information for an arbitrary path
                    710:  */
                    711: int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent)
                    712: {
                    713:   CatDataRec data;
                    714:   unsigned long parid;
                    715:   char name[HFS_MAX_FLEN + 1];
                    716: 
                    717:   if (getvol(&vol) == -1 ||
                    718:       v_resolve(&vol, path, &data, &parid, name, NULL) <= 0)
                    719:     goto fail;
                    720: 
                    721:   r_unpackdirent(parid, name, &data, ent);
                    722: 
                    723:   return 0;
                    724: 
                    725: fail:
                    726:   return -1;
                    727: }
                    728: 
                    729: /*
                    730:  * NAME:       hfs->fstat()
                    731:  * DESCRIPTION:        return catalog information for an open file
                    732:  */
                    733: int hfs_fstat(hfsfile *file, hfsdirent *ent)
                    734: {
                    735:   r_unpackdirent(file->parid, file->name, &file->cat, ent);
                    736: 
                    737:   return 0;
                    738: }
                    739: 
                    740: /*
                    741:  * NAME:       hfs->probe()
                    742:  * DESCRIPTION:        return whether a HFS filesystem is present at the given offset
                    743:  */
                    744: int hfs_probe(int fd, long long offset)
                    745: {
                    746:   return v_probe(fd, offset);
                    747: }

unix.superglobalmegacorp.com

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