summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/fs/hfs
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/fs/hfs')
-rw-r--r--qemu/roms/openbios/fs/hfs/block.c612
-rw-r--r--qemu/roms/openbios/fs/hfs/btree.c230
-rw-r--r--qemu/roms/openbios/fs/hfs/build.xml15
-rw-r--r--qemu/roms/openbios/fs/hfs/data.c476
-rw-r--r--qemu/roms/openbios/fs/hfs/file.c191
-rw-r--r--qemu/roms/openbios/fs/hfs/hfs.c747
-rw-r--r--qemu/roms/openbios/fs/hfs/hfs_fs.c593
-rw-r--r--qemu/roms/openbios/fs/hfs/include/apple.h273
-rw-r--r--qemu/roms/openbios/fs/hfs/include/block.h41
-rw-r--r--qemu/roms/openbios/fs/hfs/include/btree.h34
-rw-r--r--qemu/roms/openbios/fs/hfs/include/data.h57
-rw-r--r--qemu/roms/openbios/fs/hfs/include/file.h46
-rw-r--r--qemu/roms/openbios/fs/hfs/include/hfs.h180
-rw-r--r--qemu/roms/openbios/fs/hfs/include/libhfs.h225
-rw-r--r--qemu/roms/openbios/fs/hfs/include/low.h45
-rw-r--r--qemu/roms/openbios/fs/hfs/include/medium.h43
-rw-r--r--qemu/roms/openbios/fs/hfs/include/node.h35
-rw-r--r--qemu/roms/openbios/fs/hfs/include/record.h48
-rw-r--r--qemu/roms/openbios/fs/hfs/include/volume.h71
-rw-r--r--qemu/roms/openbios/fs/hfs/low.c157
-rw-r--r--qemu/roms/openbios/fs/hfs/medium.c84
-rw-r--r--qemu/roms/openbios/fs/hfs/node.c60
-rw-r--r--qemu/roms/openbios/fs/hfs/record.c553
-rw-r--r--qemu/roms/openbios/fs/hfs/volume.c612
24 files changed, 5428 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/hfs/block.c b/qemu/roms/openbios/fs/hfs/block.c
new file mode 100644
index 000000000..0b65a1f3b
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/block.c
@@ -0,0 +1,612 @@
+/*
+* libhfs - library for reading and writing Macintosh HFS volumes
+* Copyright (C) 1996-1998 Robert Leslie
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+* MA 02110-1301, USA.
+*
+* $Id: block.c,v 1.11 1998/11/02 22:08:52 rob Exp $
+*/
+
+#include "config.h"
+
+#include "libhfs.h"
+#include "volume.h"
+#include "block.h"
+#include "os.h"
+
+#define INUSE(b) ((b)->flags & HFS_BUCKET_INUSE)
+#define DIRTY(b) ((b)->flags & HFS_BUCKET_DIRTY)
+
+/*
+ * NAME: block->init()
+ * DESCRIPTION: initialize a volume's block cache
+ */
+int b_init(hfsvol *vol)
+{
+ bcache *cache;
+ int i;
+
+ ASSERT(vol->cache == 0);
+
+ cache = ALLOC(bcache, 1);
+ if (cache == NULL)
+ ERROR(ENOMEM, NULL);
+
+ vol->cache = cache;
+
+ cache->vol = vol;
+ cache->tail = &cache->chain[HFS_CACHESZ - 1];
+
+ cache->hits = 0;
+ cache->misses = 0;
+
+ for (i = 0; i < HFS_CACHESZ; ++i)
+ {
+ bucket *b = &cache->chain[i];
+
+ b->flags = 0;
+ b->count = 0;
+
+ b->bnum = 0;
+ b->data = &cache->pool[i];
+
+ b->cnext = b + 1;
+ b->cprev = b - 1;
+
+ b->hnext = NULL;
+ b->hprev = NULL;
+ }
+
+ cache->chain[0].cprev = cache->tail;
+ cache->tail->cnext = &cache->chain[0];
+
+ for (i = 0; i < HFS_HASHSZ; ++i)
+ cache->hash[i] = NULL;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+# ifdef DEBUG
+/*
+ * NAME: block->showstats()
+ * DESCRIPTION: output cache hit/miss ratio
+ */
+void b_showstats(const bcache *cache)
+{
+ fprintf(stderr, "BLOCK: CACHE vol 0x%lx \"%s\" hit/miss ratio = %.3f\n",
+ (unsigned long) cache->vol, cache->vol->mdb.drVN,
+ (float) cache->hits / (float) cache->misses);
+}
+
+/*
+ * NAME: block->dumpcache()
+ * DESCRIPTION: dump the cache tables for a volume
+ */
+void b_dumpcache(const bcache *cache)
+{
+ const bucket *b;
+ int i;
+
+ fprintf(stderr, "BLOCK CACHE DUMP:\n");
+
+ for (i = 0, b = cache->tail->cnext; i < HFS_CACHESZ; ++i, b = b->cnext)
+ {
+ if (INUSE(b))
+ {
+ fprintf(stderr, "\t %lu", b->bnum);
+ if (DIRTY(b))
+ fprintf(stderr, "*");
+
+ fprintf(stderr, ":%u", b->count);
+ }
+ }
+
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "BLOCK HASH DUMP:\n");
+
+ for (i = 0; i < HFS_HASHSZ; ++i)
+ {
+ int seen = 0;
+
+ for (b = cache->hash[i]; b; b = b->hnext)
+ {
+ if (! seen)
+ fprintf(stderr, " %d:", i);
+
+ if (INUSE(b))
+ {
+ fprintf(stderr, " %lu", b->bnum);
+ if (DIRTY(b))
+ fprintf(stderr, "*");
+
+ fprintf(stderr, ":%u", b->count);
+ }
+
+ seen = 1;
+ }
+
+ if (seen)
+ fprintf(stderr, "\n");
+ }
+}
+# endif
+
+/*
+ * NAME: fillchain()
+ * DESCRIPTION: fill a chain of bucket buffers with a single read
+ */
+static
+int fillchain(hfsvol *vol, bucket **bptr, unsigned int *count)
+{
+ bucket *blist[HFS_BLOCKBUFSZ], **start = bptr;
+ unsigned long bnum=-2; // XXX
+ unsigned int len, i;
+
+ for (len = 0; len < HFS_BLOCKBUFSZ &&
+ (unsigned int) (bptr - start) < *count; ++bptr)
+ {
+ if (INUSE(*bptr))
+ continue;
+
+ if (len > 0 && (*bptr)->bnum != bnum)
+ break;
+
+ blist[len++] = *bptr;
+ bnum = (*bptr)->bnum + 1;
+ }
+
+ *count = bptr - start;
+
+ if (len == 0)
+ goto done;
+ else if (len == 1)
+ {
+ if (b_readpb(vol, vol->vstart + blist[0]->bnum,
+ blist[0]->data, 1) == -1)
+ goto fail;
+ }
+ else
+ {
+ block buffer[HFS_BLOCKBUFSZ];
+
+ if (b_readpb(vol, vol->vstart + blist[0]->bnum, buffer, len) == -1)
+ goto fail;
+
+ for (i = 0; i < len; ++i)
+ memcpy(blist[i]->data, buffer[i], HFS_BLOCKSZ);
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ blist[i]->flags |= HFS_BUCKET_INUSE;
+ blist[i]->flags &= ~HFS_BUCKET_DIRTY;
+ }
+
+done:
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: compare()
+ * DESCRIPTION: comparison function for qsort of cache bucket pointers
+ */
+static
+int compare(const bucket **b1, const bucket **b2)
+{
+ long diff;
+
+ diff = (*b1)->bnum - (*b2)->bnum;
+
+ if (diff < 0)
+ return -1;
+ else if (diff > 0)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * NAME: dobuckets()
+ * DESCRIPTION: fill or flush an array of cache buckets to a volume
+ */
+static
+int dobuckets(hfsvol *vol, bucket **chain, unsigned int len,
+ int (*func)(hfsvol *, bucket **, unsigned int *))
+{
+ unsigned int count, i;
+ int result = 0;
+
+ qsort(chain, len, sizeof(*chain),
+ (int (*)(const void *, const void *)) compare);
+
+ for (i = 0; i < len; i += count)
+ {
+ count = len - i;
+ if (func(vol, chain + i, &count) == -1)
+ result = -1;
+ }
+
+ return result;
+}
+
+# define fillbuckets(vol, chain, len) dobuckets(vol, chain, len, fillchain)
+
+/*
+ * NAME: block->finish()
+ * DESCRIPTION: commit and free a volume's block cache
+ */
+int b_finish(hfsvol *vol)
+{
+ int result = 0;
+
+ if (vol->cache == NULL)
+ goto done;
+
+# ifdef DEBUG
+ b_dumpcache(vol->cache);
+# endif
+
+ FREE(vol->cache);
+ vol->cache = NULL;
+
+done:
+ return result;
+}
+
+/*
+ * NAME: findbucket()
+ * DESCRIPTION: locate a bucket in the cache, and/or its hash slot
+ */
+static
+bucket *findbucket(bcache *cache, unsigned long bnum, bucket ***hslot)
+{
+ bucket *b;
+
+ *hslot = &cache->hash[bnum & (HFS_HASHSZ - 1)];
+
+ for (b = **hslot; b; b = b->hnext)
+ {
+ if (INUSE(b) && b->bnum == bnum)
+ break;
+ }
+
+ return b;
+}
+
+/*
+ * NAME: reuse()
+ * DESCRIPTION: free a bucket for reuse, flushing if necessary
+ */
+static
+int reuse(bcache *cache, bucket *b, unsigned long bnum)
+{
+ bucket *bptr;
+ int i;
+
+# ifdef DEBUG
+ if (INUSE(b))
+ fprintf(stderr, "BLOCK: CACHE reusing bucket containing "
+ "vol 0x%lx block %lu:%u\n",
+ (unsigned long) cache->vol, b->bnum, b->count);
+# endif
+
+ if (INUSE(b) && DIRTY(b))
+ {
+ /* flush most recently unused buckets */
+
+ for (bptr = b, i = 0; i < HFS_BLOCKBUFSZ; ++i)
+ {
+ bptr = bptr->cprev;
+ }
+ }
+
+ b->flags &= ~HFS_BUCKET_INUSE;
+ b->count = 1;
+ b->bnum = bnum;
+
+ return 0;
+}
+
+/*
+ * NAME: cplace()
+ * DESCRIPTION: move a bucket to an appropriate place near head of the chain
+ */
+static
+void cplace(bcache *cache, bucket *b)
+{
+ bucket *p;
+
+ for (p = cache->tail->cnext; p->count > 1; p = p->cnext)
+ --p->count;
+
+ b->cnext->cprev = b->cprev;
+ b->cprev->cnext = b->cnext;
+
+ if (cache->tail == b)
+ cache->tail = b->cprev;
+
+ b->cprev = p->cprev;
+ b->cnext = p;
+
+ p->cprev->cnext = b;
+ p->cprev = b;
+}
+
+/*
+ * NAME: hplace()
+ * DESCRIPTION: move a bucket to the head of its hash slot
+ */
+static
+void hplace(bucket **hslot, bucket *b)
+{
+ if (*hslot != b)
+ {
+ if (b->hprev)
+ *b->hprev = b->hnext;
+ if (b->hnext)
+ b->hnext->hprev = b->hprev;
+
+ b->hprev = hslot;
+ b->hnext = *hslot;
+
+ if (*hslot)
+ (*hslot)->hprev = &b->hnext;
+
+ *hslot = b;
+ }
+}
+
+/*
+ * NAME: getbucket()
+ * DESCRIPTION: fetch a bucket from the cache, or an empty one to be filled
+ */
+static
+bucket *getbucket(bcache *cache, unsigned long bnum, int fill)
+{
+ bucket **hslot, *b, *p, *bptr,
+ *chain[HFS_BLOCKBUFSZ], **slots[HFS_BLOCKBUFSZ];
+
+ b = findbucket(cache, bnum, &hslot);
+
+ if (b)
+ {
+ /* cache hit; move towards head of cache chain */
+
+ ++cache->hits;
+
+ if (++b->count > b->cprev->count &&
+ b != cache->tail->cnext)
+ {
+ p = b->cprev;
+
+ p->cprev->cnext = b;
+ b->cnext->cprev = p;
+
+ p->cnext = b->cnext;
+ b->cprev = p->cprev;
+
+ p->cprev = b;
+ b->cnext = p;
+
+ if (cache->tail == b)
+ cache->tail = p;
+ }
+ }
+ else
+ {
+ /* cache miss; reuse least-used cache bucket */
+
+ ++cache->misses;
+
+ b = cache->tail;
+
+ if (reuse(cache, b, bnum) == -1)
+ goto fail;
+
+ if (fill)
+ {
+ unsigned int len = 0;
+
+ chain[len] = b;
+ slots[len++] = hslot;
+
+ for (bptr = b->cprev;
+ len < (HFS_BLOCKBUFSZ >> 1) && ++bnum < cache->vol->vlen;
+ bptr = bptr->cprev)
+ {
+ if (findbucket(cache, bnum, &hslot))
+ break;
+
+ if (reuse(cache, bptr, bnum) == -1)
+ goto fail;
+
+ chain[len] = bptr;
+ slots[len++] = hslot;
+ }
+
+ if (fillbuckets(cache->vol, chain, len) == -1)
+ goto fail;
+
+ while (--len)
+ {
+ cplace(cache, chain[len]);
+ hplace(slots[len], chain[len]);
+ }
+
+ hslot = slots[0];
+ }
+
+ /* move bucket to appropriate place in chain */
+
+ cplace(cache, b);
+ }
+
+ /* insert at front of hash chain */
+
+ hplace(hslot, b);
+
+ return b;
+
+fail:
+ return NULL;
+}
+
+/*
+ * NAME: block->readpb()
+ * DESCRIPTION: read blocks from the physical medium (bypassing cache)
+ */
+int b_readpb(hfsvol *vol, unsigned long bnum, block *bp, unsigned int blen)
+{
+ unsigned long nblocks;
+
+# ifdef DEBUG
+ fprintf(stderr, "BLOCK: READ vol 0x%lx block %lu",
+ (unsigned long) vol, bnum);
+ if (blen > 1)
+ fprintf(stderr, "+%u[..%lu]\n", blen - 1, bnum + blen - 1);
+ else
+ fprintf(stderr, "\n");
+# endif
+
+ nblocks = os_seek(vol->os_fd, bnum, HFS_BLOCKSZ_BITS );
+ if (nblocks == (unsigned long) -1)
+ goto fail;
+
+ if (nblocks != bnum)
+ ERROR(EIO, "block seek failed for read");
+
+ nblocks = os_read(vol->os_fd, bp, blen, HFS_BLOCKSZ_BITS);
+ if (nblocks == (unsigned long) -1)
+ goto fail;
+
+ if (nblocks != blen)
+ ERROR(EIO, "incomplete block read");
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: block->readlb()
+ * DESCRIPTION: read a logical block from a volume (or from the cache)
+ */
+int b_readlb(hfsvol *vol, unsigned long bnum, block *bp)
+{
+ if (vol->vlen > 0 && bnum >= vol->vlen)
+ ERROR(EIO, "read nonexistent logical block");
+
+ if (vol->cache)
+ {
+ bucket *b;
+
+ b = getbucket(vol->cache, bnum, 1);
+ if (b == NULL)
+ goto fail;
+
+ memcpy(bp, b->data, HFS_BLOCKSZ);
+ }
+ else
+ {
+ if (b_readpb(vol, vol->vstart + bnum, bp, 1) == -1)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: block->readab()
+ * DESCRIPTION: read a block from an allocation block from a volume
+ */
+int b_readab(hfsvol *vol, unsigned int anum, unsigned int index, block *bp)
+{
+ /* verify the allocation block exists and is marked as in-use */
+
+ if (anum >= vol->mdb.drNmAlBlks)
+ ERROR(EIO, "read nonexistent allocation block");
+ else if (vol->vbm && ! BMTST(vol->vbm, anum))
+ ERROR(EIO, "read unallocated block");
+
+ return b_readlb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + index, bp);
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: block->size()
+ * DESCRIPTION: return the number of physical blocks on a volume's medium
+ */
+unsigned long b_size(hfsvol *vol)
+{
+ unsigned long low, high, mid;
+ block b;
+
+ high = os_seek(vol->os_fd, -1, HFS_BLOCKSZ_BITS);
+
+ if (high != (unsigned long) -1 && high > 0)
+ return high;
+
+ /* manual size detection: first check there is at least 1 block in medium */
+
+ if (b_readpb(vol, 0, &b, 1) == -1)
+ ERROR(EIO, "size of medium indeterminable or empty");
+
+ for (low = 0, high = 2880;
+ high > 0 && b_readpb(vol, high - 1, &b, 1) != -1;
+ high <<= 1)
+ low = high - 1;
+
+ if (high == 0)
+ ERROR(EIO, "size of medium indeterminable or too large");
+
+ /* common case: 1440K floppy */
+
+ if (low == 2879 && b_readpb(vol, 2880, &b, 1) == -1)
+ return 2880;
+
+ /* binary search for other sizes */
+
+ while (low < high - 1)
+ {
+ mid = (low + high) >> 1;
+
+ if (b_readpb(vol, mid, &b, 1) == -1)
+ high = mid;
+ else
+ low = mid;
+ }
+
+ return low + 1;
+
+fail:
+ return 0;
+}
diff --git a/qemu/roms/openbios/fs/hfs/btree.c b/qemu/roms/openbios/fs/hfs/btree.c
new file mode 100644
index 000000000..cd5c85347
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/btree.c
@@ -0,0 +1,230 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: btree.c,v 1.10 1998/11/02 22:08:54 rob Exp $
+ */
+
+#include "config.h"
+
+#include "libhfs.h"
+#include "btree.h"
+#include "data.h"
+#include "file.h"
+#include "block.h"
+#include "node.h"
+
+/*
+ * NAME: btree->getnode()
+ * DESCRIPTION: retrieve a numbered node from a B*-tree file
+ */
+int bt_getnode(node *np, btree *bt, unsigned long nnum)
+{
+ block *bp = &np->data;
+ const byte *ptr;
+ int i;
+
+ np->bt = bt;
+ np->nnum = nnum;
+
+# if 0
+ fprintf(stderr, "BTREE: GET vol \"%s\" btree \"%s\" node %lu\n",
+ bt->f.vol->mdb.drVN, bt->f.name, np->nnum);
+# endif
+
+ /* verify the node exists and is marked as in-use */
+
+ if (nnum > 0 && nnum >= bt->hdr.bthNNodes)
+ ERROR(EIO, "read nonexistent b*-tree node");
+ else if (bt->map && ! BMTST(bt->map, nnum))
+ ERROR(EIO, "read unallocated b*-tree node");
+
+ if (f_getblock(&bt->f, nnum, bp) == -1)
+ goto fail;
+
+ ptr = *bp;
+
+ d_fetchul(&ptr, &np->nd.ndFLink);
+ d_fetchul(&ptr, &np->nd.ndBLink);
+ d_fetchsb(&ptr, &np->nd.ndType);
+ d_fetchsb(&ptr, &np->nd.ndNHeight);
+ d_fetchuw(&ptr, &np->nd.ndNRecs);
+ d_fetchsw(&ptr, &np->nd.ndResv2);
+
+ if (np->nd.ndNRecs > HFS_MAX_NRECS)
+ ERROR(EIO, "too many b*-tree node records");
+
+ i = np->nd.ndNRecs + 1;
+
+ ptr = *bp + HFS_BLOCKSZ - (2 * i);
+
+ while (i--)
+ d_fetchuw(&ptr, &np->roff[i]);
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: btree->readhdr()
+ * DESCRIPTION: read the header node of a B*-tree
+ */
+int bt_readhdr(btree *bt)
+{
+ const byte *ptr;
+ byte *map = NULL;
+ int i;
+ unsigned long nnum;
+
+ if (bt_getnode(&bt->hdrnd, bt, 0) == -1)
+ goto fail;
+
+ if (bt->hdrnd.nd.ndType != ndHdrNode ||
+ bt->hdrnd.nd.ndNRecs != 3 ||
+ bt->hdrnd.roff[0] != 0x00e ||
+ bt->hdrnd.roff[1] != 0x078 ||
+ bt->hdrnd.roff[2] != 0x0f8 ||
+ bt->hdrnd.roff[3] != 0x1f8)
+ ERROR(EIO, "malformed b*-tree header node");
+
+ /* read header record */
+
+ ptr = HFS_NODEREC(bt->hdrnd, 0);
+
+ d_fetchuw(&ptr, &bt->hdr.bthDepth);
+ d_fetchul(&ptr, &bt->hdr.bthRoot);
+ d_fetchul(&ptr, &bt->hdr.bthNRecs);
+ d_fetchul(&ptr, &bt->hdr.bthFNode);
+ d_fetchul(&ptr, &bt->hdr.bthLNode);
+ d_fetchuw(&ptr, &bt->hdr.bthNodeSize);
+ d_fetchuw(&ptr, &bt->hdr.bthKeyLen);
+ d_fetchul(&ptr, &bt->hdr.bthNNodes);
+ d_fetchul(&ptr, &bt->hdr.bthFree);
+
+ for (i = 0; i < 76; ++i)
+ d_fetchsb(&ptr, &bt->hdr.bthResv[i]);
+
+ if (bt->hdr.bthNodeSize != HFS_BLOCKSZ)
+ ERROR(EINVAL, "unsupported b*-tree node size");
+
+ /* read map record; construct btree bitmap */
+ /* don't set bt->map until we're done, since getnode() checks it */
+
+ map = ALLOC(byte, HFS_MAP1SZ);
+ if (map == NULL)
+ ERROR(ENOMEM, NULL);
+
+ memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ);
+ bt->mapsz = HFS_MAP1SZ;
+
+ /* read continuation map records, if any */
+
+ nnum = bt->hdrnd.nd.ndFLink;
+
+ while (nnum)
+ {
+ node n;
+ byte *newmap;
+
+ if (bt_getnode(&n, bt, nnum) == -1)
+ goto fail;
+
+ if (n.nd.ndType != ndMapNode ||
+ n.nd.ndNRecs != 1 ||
+ n.roff[0] != 0x00e ||
+ n.roff[1] != 0x1fa)
+ ERROR(EIO, "malformed b*-tree map node");
+
+ newmap = REALLOC(map, byte, bt->mapsz + HFS_MAPXSZ);
+ if (newmap == NULL)
+ ERROR(ENOMEM, NULL);
+
+ map = newmap;
+
+ memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ);
+ bt->mapsz += HFS_MAPXSZ;
+
+ nnum = n.nd.ndFLink;
+ }
+
+ bt->map = map;
+
+ return 0;
+
+fail:
+ FREE(map);
+ return -1;
+}
+
+
+/*
+ * NAME: btree->search()
+ * DESCRIPTION: locate a data record given a search key
+ */
+int bt_search(btree *bt, const byte *key, node *np)
+{
+ int found = 0;
+ unsigned long nnum;
+
+ nnum = bt->hdr.bthRoot;
+
+ if (nnum == 0)
+ ERROR(ENOENT, NULL);
+
+ while (1)
+ {
+ const byte *rec;
+
+ if (bt_getnode(np, bt, nnum) == -1)
+ {
+ found = -1;
+ goto fail;
+ }
+
+ found = n_search(np, key);
+
+ switch (np->nd.ndType)
+ {
+ case ndIndxNode:
+ if (np->rnum == -1)
+ ERROR(ENOENT, NULL);
+
+ rec = HFS_NODEREC(*np, np->rnum);
+ nnum = d_getul(HFS_RECDATA(rec));
+
+ break;
+
+ case ndLeafNode:
+ if (! found)
+ ERROR(ENOENT, NULL);
+
+ goto done;
+
+ default:
+ found = -1;
+ ERROR(EIO, "unexpected b*-tree node");
+ }
+ }
+
+done:
+fail:
+ return found;
+}
diff --git a/qemu/roms/openbios/fs/hfs/build.xml b/qemu/roms/openbios/fs/hfs/build.xml
new file mode 100644
index 000000000..2ac6fdbb3
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/build.xml
@@ -0,0 +1,15 @@
+<build>
+ <library name="fs" type="static" target="target">
+ <object source="block.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="btree.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="data.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="file.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="hfs.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="low.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="medium.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="node.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="record.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="volume.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ <object source="hfs_fs.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/>
+ </library>
+</build>
diff --git a/qemu/roms/openbios/fs/hfs/data.c b/qemu/roms/openbios/fs/hfs/data.c
new file mode 100644
index 000000000..a0e4a8ea7
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/data.c
@@ -0,0 +1,476 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: data.c,v 1.7 1998/11/02 22:08:57 rob Exp $
+ */
+
+#include "config.h"
+#include "data.h"
+
+#define TIMEDIFF 2082844800UL
+
+static
+time_t tzdiff = -1;
+
+static const
+unsigned char hfs_charorder[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+
+ 0x20, 0x22, 0x23, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+ 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+
+ 0x47, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69,
+ 0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f,
+ 0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1,
+ 0xa3, 0xa5, 0xa8, 0xaa, 0xab, 0xac, 0xad, 0xae,
+
+ 0x54, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69,
+ 0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f,
+ 0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1,
+ 0xa3, 0xa5, 0xa8, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
+
+ 0x4c, 0x50, 0x5c, 0x62, 0x7d, 0x81, 0x9a, 0x55,
+ 0x4a, 0x56, 0x4c, 0x4e, 0x50, 0x5c, 0x62, 0x64,
+ 0x65, 0x66, 0x6f, 0x70, 0x71, 0x72, 0x7d, 0x89,
+ 0x8a, 0x8b, 0x81, 0x83, 0x9c, 0x9d, 0x9e, 0x9a,
+
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0x95,
+ 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0x52, 0x85,
+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xcb, 0x57, 0x8c, 0xcc, 0x52, 0x85,
+
+ 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0x26,
+ 0x27, 0xd4, 0x20, 0x4a, 0x4e, 0x83, 0x87, 0x87,
+ 0xd5, 0xd6, 0x24, 0x25, 0x2d, 0x2e, 0xd7, 0xd8,
+ 0xa7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+/*
+ * NAME: data->getsb()
+ * DESCRIPTION: marshal 1 signed byte into local host format
+ */
+signed char d_getsb(register const unsigned char *ptr)
+{
+ return ptr[0];
+}
+
+/*
+ * NAME: data->getub()
+ * DESCRIPTION: marshal 1 unsigned byte into local host format
+ */
+unsigned char d_getub(register const unsigned char *ptr)
+{
+ return ptr[0];
+}
+
+/*
+ * NAME: data->getsw()
+ * DESCRIPTION: marshal 2 signed bytes into local host format
+ */
+signed short d_getsw(register const unsigned char *ptr)
+{
+ return
+ ((( signed short) ptr[0] << 8) |
+ ((unsigned short) ptr[1] << 0));
+}
+
+/*
+ * NAME: data->getuw()
+ * DESCRIPTION: marshal 2 unsigned bytes into local host format
+ */
+unsigned short d_getuw(register const unsigned char *ptr)
+{
+ return
+ (((unsigned short) ptr[0] << 8) |
+ ((unsigned short) ptr[1] << 0));
+}
+
+/*
+ * NAME: data->getsl()
+ * DESCRIPTION: marshal 4 signed bytes into local host format
+ */
+signed long d_getsl(register const unsigned char *ptr)
+{
+ return
+ ((( signed long) ptr[0] << 24) |
+ ((unsigned long) ptr[1] << 16) |
+ ((unsigned long) ptr[2] << 8) |
+ ((unsigned long) ptr[3] << 0));
+}
+
+/*
+ * NAME: data->getul()
+ * DESCRIPTION: marshal 4 unsigned bytes into local host format
+ */
+unsigned long d_getul(register const unsigned char *ptr)
+{
+ return
+ (((unsigned long) ptr[0] << 24) |
+ ((unsigned long) ptr[1] << 16) |
+ ((unsigned long) ptr[2] << 8) |
+ ((unsigned long) ptr[3] << 0));
+}
+
+/*
+ * NAME: data->putsb()
+ * DESCRIPTION: marshal 1 signed byte out in big-endian format
+ */
+void d_putsb(register unsigned char *ptr,
+ register signed char data)
+{
+ *ptr = data;
+}
+
+/*
+ * NAME: data->putub()
+ * DESCRIPTION: marshal 1 unsigned byte out in big-endian format
+ */
+void d_putub(register unsigned char *ptr,
+ register unsigned char data)
+{
+ *ptr = data;
+}
+
+/*
+ * NAME: data->putsw()
+ * DESCRIPTION: marshal 2 signed bytes out in big-endian format
+ */
+void d_putsw(register unsigned char *ptr,
+ register signed short data)
+{
+ *ptr++ = ((unsigned short) data & 0xff00) >> 8;
+ *ptr = ((unsigned short) data & 0x00ff) >> 0;
+}
+
+/*
+ * NAME: data->putuw()
+ * DESCRIPTION: marshal 2 unsigned bytes out in big-endian format
+ */
+void d_putuw(register unsigned char *ptr,
+ register unsigned short data)
+{
+ *ptr++ = (data & 0xff00) >> 8;
+ *ptr = (data & 0x00ff) >> 0;
+}
+
+/*
+ * NAME: data->putsl()
+ * DESCRIPTION: marshal 4 signed bytes out in big-endian format
+ */
+void d_putsl(register unsigned char *ptr,
+ register signed long data)
+{
+ *ptr++ = ((unsigned long) data & 0xff000000UL) >> 24;
+ *ptr++ = ((unsigned long) data & 0x00ff0000UL) >> 16;
+ *ptr++ = ((unsigned long) data & 0x0000ff00UL) >> 8;
+ *ptr = ((unsigned long) data & 0x000000ffUL) >> 0;
+}
+
+/*
+ * NAME: data->putul()
+ * DESCRIPTION: marshal 4 unsigned bytes out in big-endian format
+ */
+void d_putul(register unsigned char *ptr,
+ register unsigned long data)
+{
+ *ptr++ = (data & 0xff000000UL) >> 24;
+ *ptr++ = (data & 0x00ff0000UL) >> 16;
+ *ptr++ = (data & 0x0000ff00UL) >> 8;
+ *ptr = (data & 0x000000ffUL) >> 0;
+}
+
+/*
+ * NAME: data->fetchsb()
+ * DESCRIPTION: incrementally retrieve a signed byte of data
+ */
+void d_fetchsb(register const unsigned char **ptr,
+ register signed char *dest)
+{
+ *dest = *(*ptr)++;
+}
+
+/*
+ * NAME: data->fetchub()
+ * DESCRIPTION: incrementally retrieve an unsigned byte of data
+ */
+void d_fetchub(register const unsigned char **ptr,
+ register unsigned char *dest)
+{
+ *dest = *(*ptr)++;
+}
+
+/*
+ * NAME: data->fetchsw()
+ * DESCRIPTION: incrementally retrieve a signed word of data
+ */
+void d_fetchsw(register const unsigned char **ptr,
+ register signed short *dest)
+{
+ *dest =
+ ((( signed short) (*ptr)[0] << 8) |
+ ((unsigned short) (*ptr)[1] << 0));
+ *ptr += 2;
+}
+
+/*
+ * NAME: data->fetchuw()
+ * DESCRIPTION: incrementally retrieve an unsigned word of data
+ */
+void d_fetchuw(register const unsigned char **ptr,
+ register unsigned short *dest)
+{
+ *dest =
+ (((unsigned short) (*ptr)[0] << 8) |
+ ((unsigned short) (*ptr)[1] << 0));
+ *ptr += 2;
+}
+
+/*
+ * NAME: data->fetchsl()
+ * DESCRIPTION: incrementally retrieve a signed long word of data
+ */
+void d_fetchsl(register const unsigned char **ptr,
+ register signed long *dest)
+{
+ *dest =
+ ((( signed long) (*ptr)[0] << 24) |
+ ((unsigned long) (*ptr)[1] << 16) |
+ ((unsigned long) (*ptr)[2] << 8) |
+ ((unsigned long) (*ptr)[3] << 0));
+ *ptr += 4;
+}
+
+/*
+ * NAME: data->fetchul()
+ * DESCRIPTION: incrementally retrieve an unsigned long word of data
+ */
+void d_fetchul(register const unsigned char **ptr,
+ register unsigned long *dest)
+{
+ *dest =
+ (((unsigned long) (*ptr)[0] << 24) |
+ ((unsigned long) (*ptr)[1] << 16) |
+ ((unsigned long) (*ptr)[2] << 8) |
+ ((unsigned long) (*ptr)[3] << 0));
+ *ptr += 4;
+}
+
+/*
+ * NAME: data->storesb()
+ * DESCRIPTION: incrementally store a signed byte of data
+ */
+void d_storesb(register unsigned char **ptr,
+ register signed char data)
+{
+ *(*ptr)++ = data;
+}
+
+/*
+ * NAME: data->storeub()
+ * DESCRIPTION: incrementally store an unsigned byte of data
+ */
+void d_storeub(register unsigned char **ptr,
+ register unsigned char data)
+{
+ *(*ptr)++ = data;
+}
+
+/*
+ * NAME: data->storesw()
+ * DESCRIPTION: incrementally store a signed word of data
+ */
+void d_storesw(register unsigned char **ptr,
+ register signed short data)
+{
+ *(*ptr)++ = ((unsigned short) data & 0xff00) >> 8;
+ *(*ptr)++ = ((unsigned short) data & 0x00ff) >> 0;
+}
+
+/*
+ * NAME: data->storeuw()
+ * DESCRIPTION: incrementally store an unsigned word of data
+ */
+void d_storeuw(register unsigned char **ptr,
+ register unsigned short data)
+{
+ *(*ptr)++ = (data & 0xff00) >> 8;
+ *(*ptr)++ = (data & 0x00ff) >> 0;
+}
+
+/*
+ * NAME: data->storesl()
+ * DESCRIPTION: incrementally store a signed long word of data
+ */
+void d_storesl(register unsigned char **ptr,
+ register signed long data)
+{
+ *(*ptr)++ = ((unsigned long) data & 0xff000000UL) >> 24;
+ *(*ptr)++ = ((unsigned long) data & 0x00ff0000UL) >> 16;
+ *(*ptr)++ = ((unsigned long) data & 0x0000ff00UL) >> 8;
+ *(*ptr)++ = ((unsigned long) data & 0x000000ffUL) >> 0;
+}
+
+/*
+ * NAME: data->storeul()
+ * DESCRIPTION: incrementally store an unsigned long word of data
+ */
+void d_storeul(register unsigned char **ptr,
+ register unsigned long data)
+{
+ *(*ptr)++ = (data & 0xff000000UL) >> 24;
+ *(*ptr)++ = (data & 0x00ff0000UL) >> 16;
+ *(*ptr)++ = (data & 0x0000ff00UL) >> 8;
+ *(*ptr)++ = (data & 0x000000ffUL) >> 0;
+}
+
+/*
+ * NAME: data->fetchstr()
+ * DESCRIPTION: incrementally retrieve a string
+ */
+void d_fetchstr(const unsigned char **ptr, char *dest, unsigned size)
+{
+ unsigned len;
+
+ len = d_getub(*ptr);
+
+ if (len > 0 && len < size)
+ memcpy(dest, *ptr + 1, len);
+ else
+ len = 0;
+
+ dest[len] = 0;
+
+ *ptr += size;
+}
+
+/*
+ * NAME: data->storestr()
+ * DESCRIPTION: incrementally store a string
+ */
+void d_storestr(unsigned char **ptr, const char *src, unsigned size)
+{
+ unsigned len;
+
+ len = strlen(src);
+ if (len > --size)
+ len = 0;
+
+ d_storeub(ptr, len);
+
+ memcpy(*ptr, src, len);
+ memset(*ptr + len, 0, size - len);
+
+ *ptr += size;
+}
+
+/*
+ * NAME: data->relstring()
+ * DESCRIPTION: compare two strings as per MacOS for HFS
+ */
+int d_relstring(const char *str1, const char *str2)
+{
+ register int diff;
+
+ while (*str1 && *str2)
+ {
+ diff = hfs_charorder[(unsigned char) *str1] -
+ hfs_charorder[(unsigned char) *str2];
+
+ if (diff)
+ return diff;
+
+ ++str1, ++str2;
+ }
+
+ if (! *str1 && *str2)
+ return -1;
+ else if (*str1 && ! *str2)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * NAME: calctzdiff()
+ * DESCRIPTION: calculate the timezone difference between local time and UTC
+ */
+static
+void calctzdiff(void)
+{
+# ifdef HAVE_MKTIME
+
+ time_t t;
+ int isdst;
+ struct tm tm;
+ const struct tm *tmp;
+
+ time(&t);
+ isdst = localtime(&t)->tm_isdst;
+
+ tmp = gmtime(&t);
+ if (tmp)
+ {
+ tm = *tmp;
+ tm.tm_isdst = isdst;
+
+ tzdiff = t - mktime(&tm);
+ }
+ else
+ tzdiff = 0;
+
+# else
+
+ tzdiff = 0;
+
+# endif
+}
+
+/*
+ * NAME: data->ltime()
+ * DESCRIPTION: convert MacOS time to local time
+ */
+time_t d_ltime(unsigned long mtime)
+{
+ if (tzdiff == -1)
+ calctzdiff();
+
+ return (time_t) (mtime - TIMEDIFF) - tzdiff;
+}
+
+/*
+ * NAME: data->mtime()
+ * DESCRIPTION: convert local time to MacOS time
+ */
+unsigned long d_mtime(time_t ltime)
+{
+ if (tzdiff == -1)
+ calctzdiff();
+
+ return (unsigned long) (ltime + tzdiff) + TIMEDIFF;
+}
diff --git a/qemu/roms/openbios/fs/hfs/file.c b/qemu/roms/openbios/fs/hfs/file.c
new file mode 100644
index 000000000..a6ddb893a
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/file.c
@@ -0,0 +1,191 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: file.c,v 1.9 1998/11/02 22:08:59 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "file.h"
+#include "btree.h"
+#include "record.h"
+#include "volume.h"
+
+/*
+ * NAME: file->init()
+ * DESCRIPTION: initialize file structure
+ */
+void f_init(hfsfile *file, hfsvol *vol, long cnid, const char *name)
+{
+ int i;
+
+ file->vol = vol;
+ file->parid = 0;
+
+ strcpy(file->name, name);
+
+ file->cat.cdrType = cdrFilRec;
+ file->cat.cdrResrv2 = 0;
+
+ file->cat.u.fil.filFlags = 0;
+ file->cat.u.fil.filTyp = 0;
+
+ file->cat.u.fil.filUsrWds.fdType = 0;
+ file->cat.u.fil.filUsrWds.fdCreator = 0;
+ file->cat.u.fil.filUsrWds.fdFlags = 0;
+ file->cat.u.fil.filUsrWds.fdLocation.v = 0;
+ file->cat.u.fil.filUsrWds.fdLocation.h = 0;
+ file->cat.u.fil.filUsrWds.fdFldr = 0;
+
+ file->cat.u.fil.filFlNum = cnid;
+ file->cat.u.fil.filStBlk = 0;
+ file->cat.u.fil.filLgLen = 0;
+ file->cat.u.fil.filPyLen = 0;
+ file->cat.u.fil.filRStBlk = 0;
+ file->cat.u.fil.filRLgLen = 0;
+ file->cat.u.fil.filRPyLen = 0;
+ file->cat.u.fil.filCrDat = 0;
+ file->cat.u.fil.filMdDat = 0;
+ file->cat.u.fil.filBkDat = 0;
+
+ file->cat.u.fil.filFndrInfo.fdIconID = 0;
+ for (i = 0; i < 4; ++i)
+ file->cat.u.fil.filFndrInfo.fdUnused[i] = 0;
+ file->cat.u.fil.filFndrInfo.fdComment = 0;
+ file->cat.u.fil.filFndrInfo.fdPutAway = 0;
+
+ file->cat.u.fil.filClpSize = 0;
+
+ for (i = 0; i < 3; ++i)
+ {
+ file->cat.u.fil.filExtRec[i].xdrStABN = 0;
+ file->cat.u.fil.filExtRec[i].xdrNumABlks = 0;
+
+ file->cat.u.fil.filRExtRec[i].xdrStABN = 0;
+ file->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+
+ file->cat.u.fil.filResrv = 0;
+
+ f_selectfork(file, fkData);
+
+ file->flags = 0;
+
+ file->prev = NULL;
+ file->next = NULL;
+}
+
+/*
+ * NAME: file->selectfork()
+ * DESCRIPTION: choose a fork for file operations
+ */
+void f_selectfork(hfsfile *file, int fork)
+{
+ file->fork = fork;
+
+ memcpy(&file->ext, fork == fkData ?
+ &file->cat.u.fil.filExtRec : &file->cat.u.fil.filRExtRec,
+ sizeof(ExtDataRec));
+
+ file->fabn = 0;
+ file->pos = 0;
+}
+
+/*
+ * NAME: file->getptrs()
+ * DESCRIPTION: make pointers to the current fork's lengths and extents
+ */
+void f_getptrs(hfsfile *file, ExtDataRec **extrec,
+ unsigned long **lglen, unsigned long **pylen)
+{
+ if (file->fork == fkData)
+ {
+ if (extrec)
+ *extrec = &file->cat.u.fil.filExtRec;
+ if (lglen)
+ *lglen = &file->cat.u.fil.filLgLen;
+ if (pylen)
+ *pylen = &file->cat.u.fil.filPyLen;
+ }
+ else
+ {
+ if (extrec)
+ *extrec = &file->cat.u.fil.filRExtRec;
+ if (lglen)
+ *lglen = &file->cat.u.fil.filRLgLen;
+ if (pylen)
+ *pylen = &file->cat.u.fil.filRPyLen;
+ }
+}
+
+/*
+ * NAME: file->doblock()
+ * DESCRIPTION: read or write a numbered block from a file
+ */
+int f_doblock(hfsfile *file, unsigned long num, block *bp,
+ int (*func)(hfsvol *, unsigned int, unsigned int, block *))
+{
+ unsigned int abnum;
+ unsigned int blnum;
+ unsigned int fabn;
+ int i;
+
+ abnum = num / file->vol->lpa;
+ blnum = num % file->vol->lpa;
+
+ /* locate the appropriate extent record */
+
+ fabn = file->fabn;
+
+ if (abnum < fabn)
+ {
+ ExtDataRec *extrec;
+
+ f_getptrs(file, &extrec, NULL, NULL);
+
+ fabn = file->fabn = 0;
+ memcpy(&file->ext, extrec, sizeof(ExtDataRec));
+ }
+ else
+ abnum -= fabn;
+
+ while (1)
+ {
+ unsigned int n;
+
+ for (i = 0; i < 3; ++i)
+ {
+ n = file->ext[i].xdrNumABlks;
+
+ if (abnum < n)
+ return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp);
+
+ fabn += n;
+ abnum -= n;
+ }
+
+ if (v_extsearch(file, fabn, &file->ext, NULL) <= 0)
+ goto fail;
+
+ file->fabn = fabn;
+ }
+
+fail:
+ return -1;
+}
diff --git a/qemu/roms/openbios/fs/hfs/hfs.c b/qemu/roms/openbios/fs/hfs/hfs.c
new file mode 100644
index 000000000..0c5fefb47
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/hfs.c
@@ -0,0 +1,747 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "data.h"
+#include "block.h"
+#include "medium.h"
+#include "file.h"
+#include "btree.h"
+#include "node.h"
+#include "record.h"
+#include "volume.h"
+
+const char *hfs_error = "no error"; /* static error string */
+
+hfsvol *hfs_mounts; /* linked list of mounted volumes */
+
+static
+hfsvol *curvol; /* current volume */
+
+
+/*
+ * NAME: getvol()
+ * DESCRIPTION: validate a volume reference
+ */
+static
+int getvol(hfsvol **vol)
+{
+ if (*vol == NULL)
+ {
+ if (curvol == NULL)
+ ERROR(EINVAL, "no volume is current");
+
+ *vol = curvol;
+ }
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/* High-Level Volume Routines ============================================== */
+
+/*
+ * NAME: hfs->mount()
+ * DESCRIPTION: open an HFS volume; return volume descriptor or 0 (error)
+ */
+hfsvol *hfs_mount( int os_fd, int pnum)
+{
+ hfsvol *vol, *check;
+ int mode = HFS_MODE_RDONLY;
+
+ /* see if the volume is already mounted */
+ for (check = hfs_mounts; check; check = check->next)
+ {
+ if (check->pnum == pnum && v_same(check, os_fd) == 1)
+ {
+ vol = check;
+ goto done;
+ }
+ }
+
+ vol = ALLOC(hfsvol, 1);
+ if (vol == NULL)
+ ERROR(ENOMEM, NULL);
+
+ v_init(vol, mode);
+
+ vol->flags |= HFS_VOL_READONLY;
+ if( v_open(vol, os_fd) == -1 )
+ goto fail;
+
+ /* mount the volume */
+
+ if (v_geometry(vol, pnum) == -1 ||
+ v_mount(vol) == -1)
+ goto fail;
+
+ /* add to linked list of volumes */
+
+ vol->prev = NULL;
+ vol->next = hfs_mounts;
+
+ if (hfs_mounts)
+ hfs_mounts->prev = vol;
+
+ hfs_mounts = vol;
+
+done:
+ ++vol->refs;
+ curvol = vol;
+
+ return vol;
+
+fail:
+ if (vol)
+ {
+ v_close(vol);
+ FREE(vol);
+ }
+
+ return NULL;
+}
+
+
+/*
+ * NAME: hfs->umount()
+ * DESCRIPTION: close an HFS volume
+ */
+int hfs_umount(hfsvol *vol)
+{
+ int result = 0;
+
+ if (getvol(&vol) == -1)
+ goto fail;
+
+ if (--vol->refs)
+ {
+ goto done;
+ }
+
+ /* close all open files and directories */
+
+ while (vol->files)
+ {
+ if (hfs_close(vol->files) == -1)
+ result = -1;
+ }
+
+ while (vol->dirs)
+ {
+ if (hfs_closedir(vol->dirs) == -1)
+ result = -1;
+ }
+
+ /* close medium */
+
+ if (v_close(vol) == -1)
+ result = -1;
+
+ /* remove from linked list of volumes */
+
+ if (vol->prev)
+ vol->prev->next = vol->next;
+ if (vol->next)
+ vol->next->prev = vol->prev;
+
+ if (vol == hfs_mounts)
+ hfs_mounts = vol->next;
+ if (vol == curvol)
+ curvol = NULL;
+
+ FREE(vol);
+
+done:
+ return result;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->umountall()
+ * DESCRIPTION: unmount all mounted volumes
+ */
+void hfs_umountall(void)
+{
+ while (hfs_mounts)
+ hfs_umount(hfs_mounts);
+}
+
+/*
+ * NAME: hfs->getvol()
+ * DESCRIPTION: return a pointer to a mounted volume
+ */
+hfsvol *hfs_getvol(const char *name)
+{
+ hfsvol *vol;
+
+ if (name == NULL)
+ return curvol;
+
+ for (vol = hfs_mounts; vol; vol = vol->next)
+ {
+ if (d_relstring(name, vol->mdb.drVN) == 0)
+ return vol;
+ }
+
+ return NULL;
+}
+
+/*
+ * NAME: hfs->setvol()
+ * DESCRIPTION: change the current volume
+ */
+void hfs_setvol(hfsvol *vol)
+{
+ curvol = vol;
+}
+
+/*
+ * NAME: hfs->vstat()
+ * DESCRIPTION: return volume statistics
+ */
+int hfs_vstat(hfsvol *vol, hfsvolent *ent)
+{
+ if (getvol(&vol) == -1)
+ goto fail;
+
+ strcpy(ent->name, vol->mdb.drVN);
+
+ ent->flags = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0;
+
+ ent->totbytes = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
+ ent->freebytes = vol->mdb.drFreeBks * vol->mdb.drAlBlkSiz;
+
+ ent->alblocksz = vol->mdb.drAlBlkSiz;
+ ent->clumpsz = vol->mdb.drClpSiz;
+
+ ent->numfiles = vol->mdb.drFilCnt;
+ ent->numdirs = vol->mdb.drDirCnt;
+
+ ent->crdate = d_ltime(vol->mdb.drCrDate);
+ ent->mddate = d_ltime(vol->mdb.drLsMod);
+ ent->bkdate = d_ltime(vol->mdb.drVolBkUp);
+
+ ent->blessed = vol->mdb.drFndrInfo[0];
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/* High-Level Directory Routines =========================================== */
+
+/*
+ * NAME: hfs->chdir()
+ * DESCRIPTION: change current HFS directory
+ */
+int hfs_chdir(hfsvol *vol, const char *path)
+{
+ CatDataRec data;
+
+ if (getvol(&vol) == -1 ||
+ v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
+ goto fail;
+
+ if (data.cdrType != cdrDirRec)
+ ERROR(ENOTDIR, NULL);
+
+ vol->cwd = data.u.dir.dirDirID;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->getcwd()
+ * DESCRIPTION: return the current working directory ID
+ */
+unsigned long hfs_getcwd(hfsvol *vol)
+{
+ if (getvol(&vol) == -1)
+ return 0;
+
+ return vol->cwd;
+}
+
+/*
+ * NAME: hfs->setcwd()
+ * DESCRIPTION: set the current working directory ID
+ */
+int hfs_setcwd(hfsvol *vol, unsigned long id)
+{
+ if (getvol(&vol) == -1)
+ goto fail;
+
+ if (id == vol->cwd)
+ goto done;
+
+ /* make sure the directory exists */
+
+ if (v_getdthread(vol, id, NULL, NULL) <= 0)
+ goto fail;
+
+ vol->cwd = id;
+
+done:
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->dirinfo()
+ * DESCRIPTION: given a directory ID, return its (name and) parent ID
+ */
+int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name)
+{
+ CatDataRec thread;
+
+ if (getvol(&vol) == -1 ||
+ v_getdthread(vol, *id, &thread, NULL) <= 0)
+ goto fail;
+
+ *id = thread.u.dthd.thdParID;
+
+ if (name)
+ strcpy(name, thread.u.dthd.thdCName);
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->opendir()
+ * DESCRIPTION: prepare to read the contents of a directory
+ */
+hfsdir *hfs_opendir(hfsvol *vol, const char *path)
+{
+ hfsdir *dir = NULL;
+ CatKeyRec key;
+ CatDataRec data;
+ byte pkey[HFS_CATKEYLEN];
+
+ if (getvol(&vol) == -1)
+ goto fail;
+
+ dir = ALLOC(hfsdir, 1);
+ if (dir == NULL)
+ ERROR(ENOMEM, NULL);
+
+ dir->vol = vol;
+
+ if (*path == 0)
+ {
+ /* meta-directory containing root dirs from all mounted volumes */
+
+ dir->dirid = 0;
+ dir->vptr = hfs_mounts;
+ }
+ else
+ {
+ if (v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
+ goto fail;
+
+ if (data.cdrType != cdrDirRec)
+ ERROR(ENOTDIR, NULL);
+
+ dir->dirid = data.u.dir.dirDirID;
+ dir->vptr = NULL;
+
+ r_makecatkey(&key, dir->dirid, "");
+ r_packcatkey(&key, pkey, NULL);
+
+ if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
+ goto fail;
+ }
+
+ dir->prev = NULL;
+ dir->next = vol->dirs;
+
+ if (vol->dirs)
+ vol->dirs->prev = dir;
+
+ vol->dirs = dir;
+
+ return dir;
+
+fail:
+ FREE(dir);
+ return NULL;
+}
+
+/*
+ * NAME: hfs->readdir()
+ * DESCRIPTION: return the next entry in the directory
+ */
+int hfs_readdir(hfsdir *dir, hfsdirent *ent)
+{
+ CatKeyRec key;
+ CatDataRec data;
+ const byte *ptr;
+
+ if (dir->dirid == 0)
+ {
+ hfsvol *vol;
+ char cname[HFS_MAX_FLEN + 1];
+
+ for (vol = hfs_mounts; vol; vol = vol->next)
+ {
+ if (vol == dir->vptr)
+ break;
+ }
+
+ if (vol == NULL)
+ ERROR(ENOENT, "no more entries");
+
+ if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, NULL) <= 0 ||
+ v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
+ &data, cname, NULL) <= 0)
+ goto fail;
+
+ r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
+
+ dir->vptr = vol->next;
+
+ goto done;
+ }
+
+ if (dir->n.rnum == -1)
+ ERROR(ENOENT, "no more entries");
+
+ while (1)
+ {
+ ++dir->n.rnum;
+
+ while (dir->n.rnum >= dir->n.nd.ndNRecs)
+ {
+ if (dir->n.nd.ndFLink == 0)
+ {
+ dir->n.rnum = -1;
+ ERROR(ENOENT, "no more entries");
+ }
+
+ if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1)
+ {
+ dir->n.rnum = -1;
+ goto fail;
+ }
+
+ dir->n.rnum = 0;
+ }
+
+ ptr = HFS_NODEREC(dir->n, dir->n.rnum);
+
+ r_unpackcatkey(ptr, &key);
+
+ if (key.ckrParID != dir->dirid)
+ {
+ dir->n.rnum = -1;
+ ERROR(ENOENT, "no more entries");
+ }
+
+ r_unpackcatdata(HFS_RECDATA(ptr), &data);
+
+ switch (data.cdrType)
+ {
+ case cdrDirRec:
+ case cdrFilRec:
+ r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
+ goto done;
+
+ case cdrThdRec:
+ case cdrFThdRec:
+ break;
+
+ default:
+ dir->n.rnum = -1;
+ ERROR(EIO, "unexpected directory entry found");
+ }
+ }
+
+done:
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->closedir()
+ * DESCRIPTION: stop reading a directory
+ */
+int hfs_closedir(hfsdir *dir)
+{
+ hfsvol *vol = dir->vol;
+
+ if (dir->prev)
+ dir->prev->next = dir->next;
+ if (dir->next)
+ dir->next->prev = dir->prev;
+ if (dir == vol->dirs)
+ vol->dirs = dir->next;
+
+ FREE(dir);
+
+ return 0;
+}
+
+/* High-Level File Routines ================================================ */
+
+/*
+ * NAME: hfs->open()
+ * DESCRIPTION: prepare a file for I/O
+ */
+hfsfile *hfs_open(hfsvol *vol, const char *path)
+{
+ hfsfile *file = NULL;
+
+ if (getvol(&vol) == -1)
+ goto fail;
+
+ file = ALLOC(hfsfile, 1);
+ if (file == NULL)
+ ERROR(ENOMEM, NULL);
+
+ if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, NULL) <= 0)
+ goto fail;
+
+ if (file->cat.cdrType != cdrFilRec)
+ ERROR(EISDIR, NULL);
+
+ /* package file handle for user */
+
+ file->vol = vol;
+ file->flags = 0;
+
+ f_selectfork(file, fkData);
+
+ file->prev = NULL;
+ file->next = vol->files;
+
+ if (vol->files)
+ vol->files->prev = file;
+
+ vol->files = file;
+
+ return file;
+
+fail:
+ FREE(file);
+ return NULL;
+}
+
+/*
+ * NAME: hfs->setfork()
+ * DESCRIPTION: select file fork for I/O operations
+ */
+int hfs_setfork(hfsfile *file, int fork)
+{
+ int result = 0;
+
+ f_selectfork(file, fork ? fkRsrc : fkData);
+
+ return result;
+}
+
+/*
+ * NAME: hfs->getfork()
+ * DESCRIPTION: return the current fork for I/O operations
+ */
+int hfs_getfork(hfsfile *file)
+{
+ return file->fork != fkData;
+}
+
+/*
+ * NAME: hfs->read()
+ * DESCRIPTION: read from an open file
+ */
+unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len)
+{
+ unsigned long *lglen, count;
+ byte *ptr = buf;
+
+ f_getptrs(file, NULL, &lglen, NULL);
+
+ if (file->pos + len > *lglen)
+ len = *lglen - file->pos;
+
+ count = len;
+ while (count)
+ {
+ unsigned long bnum, offs, chunk;
+
+ bnum = file->pos >> HFS_BLOCKSZ_BITS;
+ offs = file->pos & (HFS_BLOCKSZ - 1);
+
+ chunk = HFS_BLOCKSZ - offs;
+ if (chunk > count)
+ chunk = count;
+
+ if (offs == 0 && chunk == HFS_BLOCKSZ)
+ {
+ if (f_getblock(file, bnum, (block *) ptr) == -1)
+ goto fail;
+ }
+ else
+ {
+ block b;
+
+ if (f_getblock(file, bnum, &b) == -1)
+ goto fail;
+
+ memcpy(ptr, b + offs, chunk);
+ }
+
+ ptr += chunk;
+
+ file->pos += chunk;
+ count -= chunk;
+ }
+
+ return len;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->seek()
+ * DESCRIPTION: change file seek pointer
+ */
+unsigned long hfs_seek(hfsfile *file, long offset, int from)
+{
+ unsigned long *lglen, newpos;
+
+ f_getptrs(file, NULL, &lglen, NULL);
+
+ switch (from)
+ {
+ case HFS_SEEK_SET:
+ newpos = (offset < 0) ? 0 : offset;
+ break;
+
+ case HFS_SEEK_CUR:
+ if (offset < 0 && (unsigned long) -offset > file->pos)
+ newpos = 0;
+ else
+ newpos = file->pos + offset;
+ break;
+
+ case HFS_SEEK_END:
+ if (offset < 0 && (unsigned long) -offset > *lglen)
+ newpos = 0;
+ else
+ newpos = *lglen + offset;
+ break;
+
+ default:
+ ERROR(EINVAL, NULL);
+ }
+
+ if (newpos > *lglen)
+ newpos = *lglen;
+
+ file->pos = newpos;
+
+ return newpos;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->close()
+ * DESCRIPTION: close a file
+ */
+int hfs_close(hfsfile *file)
+{
+ hfsvol *vol = file->vol;
+ int result = 0;
+
+ if (file->prev)
+ file->prev->next = file->next;
+ if (file->next)
+ file->next->prev = file->prev;
+ if (file == vol->files)
+ vol->files = file->next;
+
+ FREE(file);
+
+ return result;
+}
+
+/* High-Level Catalog Routines ============================================= */
+
+/*
+ * NAME: hfs->stat()
+ * DESCRIPTION: return catalog information for an arbitrary path
+ */
+int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent)
+{
+ CatDataRec data;
+ unsigned long parid;
+ char name[HFS_MAX_FLEN + 1];
+
+ if (getvol(&vol) == -1 ||
+ v_resolve(&vol, path, &data, &parid, name, NULL) <= 0)
+ goto fail;
+
+ r_unpackdirent(parid, name, &data, ent);
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: hfs->fstat()
+ * DESCRIPTION: return catalog information for an open file
+ */
+int hfs_fstat(hfsfile *file, hfsdirent *ent)
+{
+ r_unpackdirent(file->parid, file->name, &file->cat, ent);
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->probe()
+ * DESCRIPTION: return whether a HFS filesystem is present at the given offset
+ */
+int hfs_probe(int fd, long long offset)
+{
+ return v_probe(fd, offset);
+}
diff --git a/qemu/roms/openbios/fs/hfs/hfs_fs.c b/qemu/roms/openbios/fs/hfs/hfs_fs.c
new file mode 100644
index 000000000..2d62ec0c6
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/hfs_fs.c
@@ -0,0 +1,593 @@
+/*
+ * Creation Date: <2001/05/06 22:47:23 samuel>
+ * Time-stamp: <2004/01/12 10:24:35 samuel>
+ *
+ * /packages/hfs-files
+ *
+ * HFS world interface
+ *
+ * Copyright (C) 2001-2004 Samuel Rydh (samuel@ibrium.se)
+ * Copyright (C) 2010 Mark Cave-Ayland (mark.cave-ayland@siriusit.co.uk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "fs/fs.h"
+#include "libc/vsprintf.h"
+#include "libc/diskio.h"
+#include "libhfs.h"
+
+#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */
+#define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */
+#define MAC_OS_ROM_NAME "Mac OS ROM"
+
+#define FINDER_TYPE 0x464E4452 /* 'FNDR' */
+#define FINDER_CREATOR 0x4D414353 /* 'MACS' */
+#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
+#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
+
+#define VOLNAME_SIZE 64
+
+extern void hfs_init( void );
+
+typedef struct {
+ enum { FILE, DIR } type;
+ union {
+ hfsdir *dir;
+ hfsfile *file;
+ };
+} hfscommon;
+
+typedef struct {
+ hfsvol *vol;
+ hfscommon *common;
+} hfs_info_t;
+
+DECLARE_NODE( hfs, 0, sizeof(hfs_info_t), "+/packages/hfs-files" );
+
+/************************************************************************/
+/* Search Functions */
+/************************************************************************/
+
+static int
+_find_file( hfsvol *vol, const char *path, unsigned long type, unsigned long creator )
+{
+ hfsdirent ent;
+ hfsdir *dir;
+ int ret=1;
+
+ if( !(dir=hfs_opendir(vol, path)) )
+ return 1;
+
+ while( ret && !hfs_readdir(dir, &ent) ) {
+ if( ent.flags & HFS_ISDIR )
+ continue;
+ ret = !(*(unsigned long*)ent.u.file.type == type && *(unsigned long*)ent.u.file.creator == creator );
+ }
+
+ hfs_closedir( dir );
+ return ret;
+}
+
+
+/* ret: 0=success, 1=not_found, 2=not_a_dir */
+static int
+_search( hfsvol *vol, const char *path, const char *sname, hfsfile **ret_fd )
+{
+ hfsdir *dir;
+ hfsdirent ent;
+ int topdir=0, status = 1;
+ char *p, buf[256];
+
+ strncpy( buf, path, sizeof(buf) );
+ if( buf[strlen(buf)-1] != ':' )
+ strncat( buf, ":", sizeof(buf) );
+ buf[sizeof(buf)-1] = 0;
+ p = buf + strlen( buf );
+
+ if( !(dir=hfs_opendir(vol, path)) )
+ return 2;
+
+ /* printk("DIRECTORY: %s\n", path ); */
+
+ while( status && !hfs_readdir(dir, &ent) ) {
+ unsigned long type, creator;
+
+ *p = 0;
+ topdir = 0;
+
+ strncat( buf, ent.name, sizeof(buf) );
+ if( (status=_search(vol, buf, sname, ret_fd)) != 2 )
+ continue;
+ topdir = 1;
+
+ /* name search? */
+ if( sname ) {
+ status = strcasecmp( ent.name, sname );
+ continue;
+ }
+
+ type = *(unsigned long*)ent.u.file.type;
+ creator = *(unsigned long*)ent.u.file.creator;
+
+ /* look for Mac OS ROM, System and Finder in the same directory */
+ if( type == MAC_OS_ROM_TYPE && creator == MAC_OS_ROM_CREATOR ) {
+ if( strcasecmp(ent.name, MAC_OS_ROM_NAME) )
+ continue;
+
+ status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR )
+ || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR );
+ }
+ }
+ if( !status && topdir && ret_fd && !(*ret_fd=hfs_open(vol, buf)) ) {
+ printk("Unexpected error: failed to open matched ROM\n");
+ status = 1;
+ }
+
+ hfs_closedir( dir );
+ return status;
+}
+
+static hfsfile *
+_do_search( hfs_info_t *mi, const char *sname )
+{
+ hfsvol *vol = hfs_getvol( NULL );
+
+ mi->common->type = FILE;
+ (void)_search( vol, ":", sname, &mi->common->file );
+
+ return mi->common->file;
+}
+
+
+static const int days_month[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int days_month_leap[12] =
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static inline int is_leap(int year)
+{
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+}
+
+static void
+print_date(time_t sec)
+{
+ unsigned int second, minute, hour, month, day, year;
+ int current;
+ const int *days;
+
+ second = sec % 60;
+ sec /= 60;
+
+ minute = sec % 60;
+ sec /= 60;
+
+ hour = sec % 24;
+ sec /= 24;
+
+ year = sec * 100 / 36525;
+ sec -= year * 36525 / 100;
+ year += 1970;
+
+ days = is_leap(year) ? days_month_leap : days_month;
+
+ current = 0;
+ month = 0;
+ while (month < 12) {
+ if (sec <= current + days[month]) {
+ break;
+ }
+ current += days[month];
+ month++;
+ }
+ month++;
+
+ day = sec - current + 1;
+
+ forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
+ year, month, day, hour, minute, second);
+}
+
+/*
+static void
+dir_fs( file_desc_t *fd )
+{
+ hfscommon *common = (hfscommon*)fd;
+ hfsdirent ent;
+
+ if (common->type != DIR)
+ return;
+
+ forth_printf("\n");
+ while( !hfs_readdir(common->dir, &ent) ) {
+ forth_printf("% 10d ", ent.u.file.dsize);
+ print_date(ent.mddate);
+ if( ent.flags & HFS_ISDIR )
+ forth_printf("%s\\\n", ent.name);
+ else
+ forth_printf("%s\n", ent.name);
+ }
+}
+*/
+
+/************************************************************************/
+/* Standard package methods */
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+hfs_files_open( hfs_info_t *mi )
+{
+ int fd;
+ char *path = my_args_copy();
+
+ const char *s;
+ char buf[256];
+
+ fd = open_ih( my_parent() );
+ if ( fd == -1 ) {
+ free( path );
+ RET( 0 );
+ }
+
+ mi->vol = hfs_mount(fd, 0);
+ if (!mi->vol) {
+ RET( 0 );
+ }
+
+ if( !strncmp(path, "\\\\", 2) ) {
+ hfsvolent ent;
+
+ /* \\ is an alias for the (blessed) system folder */
+ if( hfs_vstat(mi->vol, &ent) < 0 || hfs_setcwd(mi->vol, ent.blessed) ) {
+ free(path);
+ RET( -1 );
+ }
+ path += 2;
+ } else {
+ hfs_chdir( mi->vol, ":" );
+ }
+
+ mi->common = malloc(sizeof(hfscommon));
+ if (!mi->common) {
+ free(path);
+ RET( 0 );
+ }
+
+ if (strcmp(path, "\\") == 0) {
+ /* root directory is in fact ":" */
+ mi->common->dir = hfs_opendir(mi->vol, ":");
+ mi->common->type = DIR;
+ free(path);
+ RET( -1 );
+ }
+
+ if (path[strlen(path) - 1] == '\\') {
+ path[strlen(path) - 1] = 0;
+ }
+
+ for( path-- ;; ) {
+ int n;
+
+ s = ++path;
+ path = strchr(s, '\\');
+ if( !path || !path[1])
+ break;
+ n = MIN( sizeof(buf)-1, (path-s) );
+ if( !n )
+ continue;
+
+ strncpy( buf, s, n );
+ buf[n] = 0;
+ if( hfs_chdir(mi->vol, buf) ) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ }
+
+ /* support the ':filetype' syntax */
+ if( *s == ':' ) {
+ unsigned long id, oldid = hfs_getcwd(mi->vol);
+ hfsdirent ent;
+ hfsdir *dir;
+
+ s++;
+ id = oldid;
+ hfs_dirinfo( mi->vol, &id, buf );
+ hfs_setcwd( mi->vol, id );
+
+ if( !(dir=hfs_opendir(mi->vol, buf)) ) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ hfs_setcwd( mi->vol, oldid );
+
+ while( !hfs_readdir(dir, &ent) ) {
+ if( ent.flags & HFS_ISDIR )
+ continue;
+ if( !strncmp(s, ent.u.file.type, 4) ) {
+ mi->common->type = FILE;
+ mi->common->file = hfs_open( mi->vol, ent.name );
+ break;
+ }
+ }
+ hfs_closedir( dir );
+ free(path);
+ RET( -1 );
+ }
+
+ mi->common->dir = hfs_opendir(mi->vol, s);
+ if (!mi->common->dir) {
+ mi->common->file = hfs_open( mi->vol, s );
+ if (mi->common->file == NULL) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ mi->common->type = FILE;
+ free(path);
+ RET( -1 );
+ }
+ mi->common->type = DIR;
+ free(path);
+
+ RET( -1 );
+}
+
+/* ( -- ) */
+static void
+hfs_files_close( hfs_info_t *mi )
+{
+ hfscommon *common = mi->common;
+ if (common->type == FILE)
+ hfs_close( common->file );
+ else if (common->type == DIR)
+ hfs_closedir( common->dir );
+ free(common);
+}
+
+/* ( buf len -- actlen ) */
+static void
+hfs_files_read( hfs_info_t *mi )
+{
+ int count = POP();
+ char *buf = (char *)cell2pointer(POP());
+
+ hfscommon *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ RET ( hfs_read( common->file, buf, count ) );
+}
+
+/* ( pos.d -- status ) */
+static void
+hfs_files_seek( hfs_info_t *mi )
+{
+ long long pos = DPOP();
+ int offs = (int)pos;
+ int whence = SEEK_SET;
+ int ret;
+ hfscommon *common = mi->common;
+
+ if (common->type != FILE)
+ RET( -1 );
+
+ switch( whence ) {
+ case SEEK_END:
+ whence = HFS_SEEK_END;
+ break;
+ default:
+ case SEEK_SET:
+ whence = HFS_SEEK_SET;
+ break;
+ }
+
+ ret = hfs_seek( common->file, offs, whence );
+ if (ret != -1)
+ RET( 0 );
+ else
+ RET( -1 );
+}
+
+/* ( addr -- size ) */
+static void
+hfs_files_load( hfs_info_t *mi )
+{
+ char *buf = (char *)cell2pointer(POP());
+ int count;
+
+ hfscommon *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ /* Seek to the end in order to get the file size */
+ hfs_seek(common->file, 0, HFS_SEEK_END);
+ count = common->file->pos;
+ hfs_seek(common->file, 0, HFS_SEEK_SET);
+
+ RET ( hfs_read( common->file, buf, count ) );
+}
+
+/* ( -- success? ) */
+static void
+hfs_files_open_nwrom( hfs_info_t *mi )
+{
+ /* Switch to an existing ROM image file on the fs! */
+ if ( _do_search( mi, NULL ) )
+ RET( -1 );
+
+ RET( 0 );
+}
+
+/* ( -- cstr ) */
+static void
+hfs_files_get_path( hfs_info_t *mi )
+{
+ char buf[256], buf2[256];
+ hfscommon *common = mi->common;
+ hfsvol *vol = hfs_getvol( NULL );
+ hfsdirent ent;
+ int start, ns;
+ unsigned long id;
+
+ if (common->type != FILE)
+ RET( 0 );
+
+ hfs_fstat( common->file, &ent );
+ start = sizeof(buf) - strlen(ent.name) - 1;
+ if( start <= 0 )
+ RET ( 0 );
+ strcpy( buf+start, ent.name );
+ buf[--start] = '\\';
+
+ ns = start;
+ for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) {
+ start = ns;
+ ns -= strlen(buf2);
+ if( ns <= 0 )
+ RET( 0 );
+ strcpy( buf+ns, buf2 );
+ buf[--ns] = buf[start] = '\\';
+ }
+ if( strlen(buf) >= sizeof(buf) )
+ RET( 0 );
+
+ RET( pointer2cell(strdup(buf+start)) );
+}
+
+/* ( -- cstr ) */
+static void
+hfs_files_get_fstype( hfs_info_t *mi )
+{
+ PUSH( pointer2cell(strdup("HFS")) );
+}
+
+/* ( -- cstr|0 ) */
+static void
+hfs_files_volume_name( hfs_info_t *mi )
+{
+ int fd;
+ char *volname = malloc(VOLNAME_SIZE);
+
+ fd = open_ih(my_self());
+ if (fd >= 0) {
+ get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
+ close_io(fd);
+ } else {
+ volname[0] = '\0';
+ }
+
+ PUSH(pointer2cell(volname));
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+hfs_files_dir( hfs_info_t *dummy )
+{
+ hfsvol *volume;
+ hfscommon *common;
+ hfsdirent ent;
+ int i;
+ int fd;
+
+ ihandle_t ih = POP();
+ char *path = pop_fstr_copy();
+
+ fd = open_ih( ih );
+ if ( fd == -1 ) {
+ free( path );
+ return;
+ }
+
+ volume = hfs_mount(fd, 0);
+ if (!volume) {
+ return;
+ }
+
+ common = malloc(sizeof(hfscommon));
+
+ /* HFS paths are colon separated, not backslash separated */
+ for (i = 0; i < strlen(path); i++)
+ if (path[i] == '\\')
+ path[i] = ':';
+
+ common->dir = hfs_opendir(volume, path);
+
+ forth_printf("\n");
+ while( !hfs_readdir(common->dir, &ent) ) {
+ forth_printf("% 10ld ", ent.u.file.dsize);
+ print_date(ent.mddate);
+ if( ent.flags & HFS_ISDIR )
+ forth_printf("%s\\\n", ent.name);
+ else
+ forth_printf("%s\n", ent.name);
+ }
+
+ hfs_closedir( common->dir );
+ hfs_umount( volume );
+
+ close_io( fd );
+
+ free( common );
+ free( path );
+}
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+hfs_files_probe( hfs_info_t *dummy )
+{
+ ihandle_t ih = POP_ih();
+ long long offs = DPOP();
+ int fd, ret = 0;
+
+ fd = open_ih(ih);
+ if (fd >= 0) {
+ if (hfs_probe(fd, offs)) {
+ ret = -1;
+ }
+ close_io(fd);
+ } else {
+ ret = -1;
+ }
+
+ RET (ret);
+}
+
+static void
+hfs_initializer( hfs_info_t *dummy )
+{
+ fword("register-fs-package");
+}
+
+NODE_METHODS( hfs ) = {
+ { "probe", hfs_files_probe },
+ { "open", hfs_files_open },
+ { "close", hfs_files_close },
+ { "read", hfs_files_read },
+ { "seek", hfs_files_seek },
+ { "load", hfs_files_load },
+ { "dir", hfs_files_dir },
+
+ /* special */
+ { "open-nwrom", hfs_files_open_nwrom },
+ { "get-path", hfs_files_get_path },
+ { "get-fstype", hfs_files_get_fstype },
+ { "volume-name", hfs_files_volume_name },
+
+ { NULL, hfs_initializer },
+};
+
+void
+hfs_init( void )
+{
+ REGISTER_NODE( hfs );
+}
diff --git a/qemu/roms/openbios/fs/hfs/include/apple.h b/qemu/roms/openbios/fs/hfs/include/apple.h
new file mode 100644
index 000000000..3de581d82
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/apple.h
@@ -0,0 +1,273 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: apple.h,v 1.1 1998/04/11 08:27:11 rob Exp $
+ */
+
+typedef signed char Char;
+typedef unsigned char UChar;
+typedef signed char SignedByte;
+typedef signed short Integer;
+typedef unsigned short UInteger;
+typedef signed long LongInt;
+typedef unsigned long ULongInt;
+typedef char Str15[16];
+typedef char Str31[32];
+typedef long OSType;
+
+typedef struct {
+ Integer sbSig; /* device signature (should be 0x4552) */
+ Integer sbBlkSize; /* block size of the device (in bytes) */
+ LongInt sbBlkCount; /* number of blocks on the device */
+ Integer sbDevType; /* reserved */
+ Integer sbDevId; /* reserved */
+ LongInt sbData; /* reserved */
+ Integer sbDrvrCount; /* number of driver descriptor entries */
+ LongInt ddBlock; /* first driver's starting block */
+ Integer ddSize; /* size of the driver, in 512-byte blocks */
+ Integer ddType; /* driver operating system type (MacOS = 1) */
+ Integer ddPad[243]; /* additional drivers, if any */
+} Block0;
+
+typedef struct {
+ Integer pmSig; /* partition signature (0x504d or 0x5453) */
+ Integer pmSigPad; /* reserved */
+ LongInt pmMapBlkCnt; /* number of blocks in partition map */
+ LongInt pmPyPartStart; /* first physical block of partition */
+ LongInt pmPartBlkCnt; /* number of blocks in partition */
+ Char pmPartName[33]; /* partition name */
+ Char pmParType[33]; /* partition type */
+ LongInt pmLgDataStart; /* first logical block of data area */
+ LongInt pmDataCnt; /* number of blocks in data area */
+ LongInt pmPartStatus; /* partition status information */
+ LongInt pmLgBootStart; /* first logical block of boot code */
+ LongInt pmBootSize; /* size of boot code, in bytes */
+ LongInt pmBootAddr; /* boot code load address */
+ LongInt pmBootAddr2; /* reserved */
+ LongInt pmBootEntry; /* boot code entry point */
+ LongInt pmBootEntry2; /* reserved */
+ LongInt pmBootCksum; /* boot code checksum */
+ Char pmProcessor[17];/* processor type */
+ Integer pmPad[188]; /* reserved */
+} Partition;
+
+typedef struct {
+ Integer bbID; /* boot blocks signature */
+ LongInt bbEntry; /* entry point to boot code */
+ Integer bbVersion; /* boot blocks version number */
+ Integer bbPageFlags; /* used internally */
+ Str15 bbSysName; /* System filename */
+ Str15 bbShellName; /* Finder filename */
+ Str15 bbDbg1Name; /* debugger filename */
+ Str15 bbDbg2Name; /* debugger filename */
+ Str15 bbScreenName; /* name of startup screen */
+ Str15 bbHelloName; /* name of startup program */
+ Str15 bbScrapName; /* name of system scrap file */
+ Integer bbCntFCBs; /* number of FCBs to allocate */
+ Integer bbCntEvts; /* number of event queue elements */
+ LongInt bb128KSHeap; /* system heap size on 128K Mac */
+ LongInt bb256KSHeap; /* used internally */
+ LongInt bbSysHeapSize; /* system heap size on all machines */
+ Integer filler; /* reserved */
+ LongInt bbSysHeapExtra; /* additional system heap space */
+ LongInt bbSysHeapFract; /* fraction of RAM for system heap */
+} BootBlkHdr;
+
+typedef struct {
+ UInteger xdrStABN; /* first allocation block */
+ UInteger xdrNumABlks; /* number of allocation blocks */
+} ExtDescriptor;
+
+typedef ExtDescriptor ExtDataRec[3];
+
+typedef struct {
+ SignedByte xkrKeyLen; /* key length */
+ SignedByte xkrFkType; /* fork type (0x00/0xff == data/resource */
+ ULongInt xkrFNum; /* file number */
+ UInteger xkrFABN; /* starting file allocation block */
+} ExtKeyRec;
+
+typedef struct {
+ SignedByte ckrKeyLen; /* key length */
+ SignedByte ckrResrv1; /* reserved */
+ ULongInt ckrParID; /* parent directory ID */
+ Str31 ckrCName; /* catalog node name */
+} CatKeyRec;
+
+typedef struct {
+ Integer v; /* vertical coordinate */
+ Integer h; /* horizontal coordinate */
+} Point;
+
+typedef struct {
+ Integer top; /* top edge of rectangle */
+ Integer left; /* left edge */
+ Integer bottom; /* bottom edge */
+ Integer right; /* right edge */
+} Rect;
+
+typedef struct {
+ Rect frRect; /* folder's rectangle */
+ Integer frFlags; /* flags */
+ Point frLocation; /* folder's location */
+ Integer frView; /* folder's view */
+} DInfo;
+
+typedef struct {
+ Point frScroll; /* scroll position */
+ LongInt frOpenChain; /* directory ID chain of open folders */
+ Integer frUnused; /* reserved */
+ Integer frComment; /* comment ID */
+ LongInt frPutAway; /* directory ID */
+} DXInfo;
+
+typedef struct {
+ OSType fdType; /* file type */
+ OSType fdCreator; /* file's creator */
+ Integer fdFlags; /* flags */
+ Point fdLocation; /* file's location */
+ Integer fdFldr; /* file's window */
+} FInfo;
+
+typedef struct {
+ Integer fdIconID; /* icon ID */
+ Integer fdUnused[4]; /* reserved */
+ Integer fdComment; /* comment ID */
+ LongInt fdPutAway; /* home directory ID */
+} FXInfo;
+
+typedef struct {
+ Integer drSigWord; /* volume signature (0x4244 for HFS) */
+ LongInt drCrDate; /* date and time of volume creation */
+ LongInt drLsMod; /* date and time of last modification */
+ Integer drAtrb; /* volume attributes */
+ UInteger drNmFls; /* number of files in root directory */
+ UInteger drVBMSt; /* first block of volume bit map (always 3) */
+ UInteger drAllocPtr; /* start of next allocation search */
+ UInteger drNmAlBlks; /* number of allocation blocks in volume */
+ ULongInt drAlBlkSiz; /* size (in bytes) of allocation blocks */
+ ULongInt drClpSiz; /* default clump size */
+ UInteger drAlBlSt; /* first allocation block in volume */
+ LongInt drNxtCNID; /* next unused catalog node ID (dir/file ID) */
+ UInteger drFreeBks; /* number of unused allocation blocks */
+ char drVN[28]; /* volume name (1-27 chars) */
+ LongInt drVolBkUp; /* date and time of last backup */
+ Integer drVSeqNum; /* volume backup sequence number */
+ ULongInt drWrCnt; /* volume write count */
+ ULongInt drXTClpSiz; /* clump size for extents overflow file */
+ ULongInt drCTClpSiz; /* clump size for catalog file */
+ UInteger drNmRtDirs; /* number of directories in root directory */
+ ULongInt drFilCnt; /* number of files in volume */
+ ULongInt drDirCnt; /* number of directories in volume */
+ LongInt drFndrInfo[8]; /* information used by the Finder */
+ UInteger drEmbedSigWord; /* type of embedded volume */
+ ExtDescriptor drEmbedExtent; /* location of embedded volume */
+ ULongInt drXTFlSize; /* size (in bytes) of extents overflow file */
+ ExtDataRec drXTExtRec; /* first extent record for extents file */
+ ULongInt drCTFlSize; /* size (in bytes) of catalog file */
+ ExtDataRec drCTExtRec; /* first extent record for catalog file */
+} MDB;
+
+typedef enum {
+ cdrDirRec = 1,
+ cdrFilRec = 2,
+ cdrThdRec = 3,
+ cdrFThdRec = 4
+} CatDataType;
+
+typedef struct {
+ SignedByte cdrType; /* record type */
+ SignedByte cdrResrv2; /* reserved */
+ union {
+ struct { /* cdrDirRec */
+ Integer dirFlags; /* directory flags */
+ UInteger dirVal; /* directory valence */
+ ULongInt dirDirID; /* directory ID */
+ LongInt dirCrDat; /* date and time of creation */
+ LongInt dirMdDat; /* date and time of last modification */
+ LongInt dirBkDat; /* date and time of last backup */
+ DInfo dirUsrInfo; /* Finder information */
+ DXInfo dirFndrInfo; /* additional Finder information */
+ LongInt dirResrv[4]; /* reserved */
+ } dir;
+ struct { /* cdrFilRec */
+ SignedByte
+ filFlags; /* file flags */
+ SignedByte
+ filTyp; /* file type */
+ FInfo filUsrWds; /* Finder information */
+ ULongInt filFlNum; /* file ID */
+ UInteger filStBlk; /* first alloc block of data fork */
+ ULongInt filLgLen; /* logical EOF of data fork */
+ ULongInt filPyLen; /* physical EOF of data fork */
+ UInteger filRStBlk; /* first alloc block of resource fork */
+ ULongInt filRLgLen; /* logical EOF of resource fork */
+ ULongInt filRPyLen; /* physical EOF of resource fork */
+ LongInt filCrDat; /* date and time of creation */
+ LongInt filMdDat; /* date and time of last modification */
+ LongInt filBkDat; /* date and time of last backup */
+ FXInfo filFndrInfo; /* additional Finder information */
+ UInteger filClpSize; /* file clump size */
+ ExtDataRec
+ filExtRec; /* first data fork extent record */
+ ExtDataRec
+ filRExtRec; /* first resource fork extent record */
+ LongInt filResrv; /* reserved */
+ } fil;
+ struct { /* cdrThdRec */
+ LongInt thdResrv[2]; /* reserved */
+ ULongInt thdParID; /* parent ID for this directory */
+ Str31 thdCName; /* name of this directory */
+ } dthd;
+ struct { /* cdrFThdRec */
+ LongInt fthdResrv[2]; /* reserved */
+ ULongInt fthdParID; /* parent ID for this file */
+ Str31 fthdCName; /* name of this file */
+ } fthd;
+ } u;
+} CatDataRec;
+
+typedef struct {
+ ULongInt ndFLink; /* forward link */
+ ULongInt ndBLink; /* backward link */
+ SignedByte ndType; /* node type */
+ SignedByte ndNHeight; /* node level */
+ UInteger ndNRecs; /* number of records in node */
+ Integer ndResv2; /* reserved */
+} NodeDescriptor;
+
+enum {
+ ndIndxNode = (SignedByte) 0x00,
+ ndHdrNode = (SignedByte) 0x01,
+ ndMapNode = (SignedByte) 0x02,
+ ndLeafNode = (SignedByte) 0xff
+};
+
+typedef struct {
+ UInteger bthDepth; /* current depth of tree */
+ ULongInt bthRoot; /* number of root node */
+ ULongInt bthNRecs; /* number of leaf records in tree */
+ ULongInt bthFNode; /* number of first leaf node */
+ ULongInt bthLNode; /* number of last leaf node */
+ UInteger bthNodeSize; /* size of a node */
+ UInteger bthKeyLen; /* maximum length of a key */
+ ULongInt bthNNodes; /* total number of nodes in tree */
+ ULongInt bthFree; /* number of free nodes */
+ SignedByte bthResv[76]; /* reserved */
+} BTHdrRec;
diff --git a/qemu/roms/openbios/fs/hfs/include/block.h b/qemu/roms/openbios/fs/hfs/include/block.h
new file mode 100644
index 000000000..d7e764518
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/block.h
@@ -0,0 +1,41 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: block.h,v 1.10 1998/11/02 22:08:53 rob Exp $
+ */
+
+int b_init(hfsvol *);
+int b_flush(hfsvol *);
+int b_finish(hfsvol *);
+
+int b_readpb(hfsvol *, unsigned long, block *, unsigned int);
+int b_writepb(hfsvol *, unsigned long, const block *, unsigned int);
+
+int b_readlb(hfsvol *, unsigned long, block *);
+int b_writelb(hfsvol *, unsigned long, const block *);
+
+int b_readab(hfsvol *, unsigned int, unsigned int, block *);
+int b_writeab(hfsvol *, unsigned int, unsigned int, const block *);
+
+unsigned long b_size(hfsvol *);
+
+# ifdef DEBUG
+void b_showstats(const bcache *);
+void b_dumpcache(const bcache *);
+# endif
diff --git a/qemu/roms/openbios/fs/hfs/include/btree.h b/qemu/roms/openbios/fs/hfs/include/btree.h
new file mode 100644
index 000000000..36660f538
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/btree.h
@@ -0,0 +1,34 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: btree.h,v 1.8 1998/11/02 22:08:55 rob Exp $
+ */
+
+int bt_getnode(node *, btree *, unsigned long);
+int bt_putnode(node *);
+
+int bt_readhdr(btree *);
+int bt_writehdr(btree *);
+
+int bt_space(btree *, unsigned int);
+
+int bt_insert(btree *, const byte *, unsigned int);
+int bt_delete(btree *, const byte *);
+
+int bt_search(btree *, const byte *, node *);
diff --git a/qemu/roms/openbios/fs/hfs/include/data.h b/qemu/roms/openbios/fs/hfs/include/data.h
new file mode 100644
index 000000000..f3e20008f
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/data.h
@@ -0,0 +1,57 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: data.h,v 1.7 1998/11/02 22:08:58 rob Exp $
+ */
+
+ signed char d_getsb(register const unsigned char *);
+unsigned char d_getub(register const unsigned char *);
+ signed short d_getsw(register const unsigned char *);
+unsigned short d_getuw(register const unsigned char *);
+ signed long d_getsl(register const unsigned char *);
+unsigned long d_getul(register const unsigned char *);
+
+void d_putsb(register unsigned char *, register signed char);
+void d_putub(register unsigned char *, register unsigned char);
+void d_putsw(register unsigned char *, register signed short);
+void d_putuw(register unsigned char *, register unsigned short);
+void d_putsl(register unsigned char *, register signed long);
+void d_putul(register unsigned char *, register unsigned long);
+
+void d_fetchsb(register const unsigned char **, register signed char *);
+void d_fetchub(register const unsigned char **, register unsigned char *);
+void d_fetchsw(register const unsigned char **, register signed short *);
+void d_fetchuw(register const unsigned char **, register unsigned short *);
+void d_fetchsl(register const unsigned char **, register signed long *);
+void d_fetchul(register const unsigned char **, register unsigned long *);
+
+void d_storesb(register unsigned char **, register signed char);
+void d_storeub(register unsigned char **, register unsigned char);
+void d_storesw(register unsigned char **, register signed short);
+void d_storeuw(register unsigned char **, register unsigned short);
+void d_storesl(register unsigned char **, register signed long);
+void d_storeul(register unsigned char **, register unsigned long);
+
+void d_fetchstr(const unsigned char **, char *, unsigned);
+void d_storestr(unsigned char **, const char *, unsigned);
+
+int d_relstring(const char *, const char *);
+
+time_t d_ltime(unsigned long);
+unsigned long d_mtime(time_t);
diff --git a/qemu/roms/openbios/fs/hfs/include/file.h b/qemu/roms/openbios/fs/hfs/include/file.h
new file mode 100644
index 000000000..dacdc4800
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/file.h
@@ -0,0 +1,46 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: file.h,v 1.6 1998/04/11 08:27:12 rob Exp $
+ */
+
+enum {
+ fkData = 0x00,
+ fkRsrc = 0xff
+};
+
+void f_init(hfsfile *, hfsvol *, long, const char *);
+void f_selectfork(hfsfile *, int);
+void f_getptrs(hfsfile *, ExtDataRec **, unsigned long **, unsigned long **);
+
+int f_doblock(hfsfile *, unsigned long, block *,
+ int (*)(hfsvol *, unsigned int, unsigned int, block *));
+
+# define f_getblock(file, num, bp) \
+ f_doblock((file), (num), (bp), b_readab)
+# define f_putblock(file, num, bp) \
+ f_doblock((file), (num), (bp), \
+ (int (*)(hfsvol *, unsigned int, unsigned int, block *)) \
+ b_writeab)
+
+int f_addextent(hfsfile *, ExtDescriptor *);
+long f_alloc(hfsfile *);
+
+int f_trunc(hfsfile *);
+int f_flush(hfsfile *);
diff --git a/qemu/roms/openbios/fs/hfs/include/hfs.h b/qemu/roms/openbios/fs/hfs/include/hfs.h
new file mode 100644
index 000000000..9996cc8dd
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/hfs.h
@@ -0,0 +1,180 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: hfs.h,v 1.11 1998/11/02 22:09:01 rob Exp $
+ */
+
+# define HFS_BLOCKSZ 512
+# define HFS_BLOCKSZ_BITS 9
+
+# define HFS_MAX_FLEN 31
+# define HFS_MAX_VLEN 27
+
+typedef struct _hfsvol_ hfsvol;
+typedef struct _hfsfile_ hfsfile;
+typedef struct _hfsdir_ hfsdir;
+
+typedef struct {
+ char name[HFS_MAX_VLEN + 1]; /* name of volume (MacOS Standard Roman) */
+ int flags; /* volume flags */
+
+ unsigned long totbytes; /* total bytes on volume */
+ unsigned long freebytes; /* free bytes on volume */
+
+ unsigned long alblocksz; /* volume allocation block size */
+ unsigned long clumpsz; /* default file clump size */
+
+ unsigned long numfiles; /* number of files in volume */
+ unsigned long numdirs; /* number of directories in volume */
+
+ time_t crdate; /* volume creation date */
+ time_t mddate; /* last volume modification date */
+ time_t bkdate; /* last volume backup date */
+
+ unsigned long blessed; /* CNID of MacOS System Folder */
+} hfsvolent;
+
+typedef struct {
+ char name[HFS_MAX_FLEN + 1]; /* catalog name (MacOS Standard Roman) */
+ int flags; /* bit flags */
+ unsigned long cnid; /* catalog node id (CNID) */
+ unsigned long parid; /* CNID of parent directory */
+
+ time_t crdate; /* date of creation */
+ time_t mddate; /* date of last modification */
+ time_t bkdate; /* date of last backup */
+
+ short fdflags; /* Macintosh Finder flags */
+
+ struct {
+ signed short v; /* Finder icon vertical coordinate */
+ signed short h; /* horizontal coordinate */
+ } fdlocation;
+
+ union {
+ struct {
+ unsigned long dsize; /* size of data fork */
+ unsigned long rsize; /* size of resource fork */
+
+ char type[5]; /* file type code (plus null) */
+ char creator[5]; /* file creator code (plus null) */
+ } file;
+
+ struct {
+ unsigned short valence; /* number of items in directory */
+
+ struct {
+ signed short top; /* top edge of folder's rectangle */
+ signed short left; /* left edge */
+ signed short bottom; /* bottom edge */
+ signed short right; /* right edge */
+ } rect;
+ } dir;
+ } u;
+} hfsdirent;
+
+# define HFS_ISDIR 0x0001
+# define HFS_ISLOCKED 0x0002
+
+# define HFS_CNID_ROOTPAR 1
+# define HFS_CNID_ROOTDIR 2
+# define HFS_CNID_EXT 3
+# define HFS_CNID_CAT 4
+# define HFS_CNID_BADALLOC 5
+
+# define HFS_FNDR_ISONDESK (1 << 0)
+# define HFS_FNDR_COLOR 0x0e
+# define HFS_FNDR_COLORRESERVED (1 << 4)
+# define HFS_FNDR_REQUIRESSWITCHLAUNCH (1 << 5)
+# define HFS_FNDR_ISSHARED (1 << 6)
+# define HFS_FNDR_HASNOINITS (1 << 7)
+# define HFS_FNDR_HASBEENINITED (1 << 8)
+# define HFS_FNDR_RESERVED (1 << 9)
+# define HFS_FNDR_HASCUSTOMICON (1 << 10)
+# define HFS_FNDR_ISSTATIONERY (1 << 11)
+# define HFS_FNDR_NAMELOCKED (1 << 12)
+# define HFS_FNDR_HASBUNDLE (1 << 13)
+# define HFS_FNDR_ISINVISIBLE (1 << 14)
+# define HFS_FNDR_ISALIAS (1 << 15)
+
+extern const char *hfs_error;
+extern const unsigned char hfs_charorder[];
+
+# define HFS_MODE_RDONLY 0
+# define HFS_MODE_RDWR 1
+# define HFS_MODE_ANY 2
+
+# define HFS_MODE_MASK 0x0003
+
+# define HFS_OPT_NOCACHE 0x0100
+# define HFS_OPT_2048 0x0200
+# define HFS_OPT_ZERO 0x0400
+
+# define HFS_SEEK_SET 0
+# define HFS_SEEK_CUR 1
+# define HFS_SEEK_END 2
+
+hfsvol *hfs_mount( int os_fd, int);
+int hfs_flush(hfsvol *);
+void hfs_flushall(void);
+int hfs_umount(hfsvol *);
+void hfs_umountall(void);
+hfsvol *hfs_getvol(const char *);
+void hfs_setvol(hfsvol *);
+
+int hfs_vstat(hfsvol *, hfsvolent *);
+int hfs_vsetattr(hfsvol *, hfsvolent *);
+
+int hfs_chdir(hfsvol *, const char *);
+unsigned long hfs_getcwd(hfsvol *);
+int hfs_setcwd(hfsvol *, unsigned long);
+int hfs_dirinfo(hfsvol *, unsigned long *, char *);
+
+hfsdir *hfs_opendir(hfsvol *, const char *);
+int hfs_readdir(hfsdir *, hfsdirent *);
+int hfs_closedir(hfsdir *);
+
+hfsfile *hfs_create(hfsvol *, const char *, const char *, const char *);
+hfsfile *hfs_open(hfsvol *, const char *);
+int hfs_setfork(hfsfile *, int);
+int hfs_getfork(hfsfile *);
+unsigned long hfs_read(hfsfile *, void *, unsigned long);
+unsigned long hfs_write(hfsfile *, const void *, unsigned long);
+int hfs_truncate(hfsfile *, unsigned long);
+unsigned long hfs_seek(hfsfile *, long, int);
+int hfs_close(hfsfile *);
+
+int hfs_stat(hfsvol *, const char *, hfsdirent *);
+int hfs_fstat(hfsfile *, hfsdirent *);
+int hfs_setattr(hfsvol *, const char *, const hfsdirent *);
+int hfs_fsetattr(hfsfile *, const hfsdirent *);
+
+int hfs_mkdir(hfsvol *, const char *);
+int hfs_rmdir(hfsvol *, const char *);
+
+int hfs_delete(hfsvol *, const char *);
+int hfs_rename(hfsvol *, const char *, const char *);
+
+int hfs_zero(const char *, unsigned int, unsigned long *);
+int hfs_mkpart(const char *, unsigned long);
+int hfs_nparts(const char *);
+
+int hfs_format(const char *, int, int,
+ const char *, unsigned int, const unsigned long []);
+int hfs_probe(int fd, long long offset);
diff --git a/qemu/roms/openbios/fs/hfs/include/libhfs.h b/qemu/roms/openbios/fs/hfs/include/libhfs.h
new file mode 100644
index 000000000..f46f43832
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/libhfs.h
@@ -0,0 +1,225 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: libhfs.h,v 1.7 1998/11/02 22:09:02 rob Exp $
+ */
+
+# include "hfs.h"
+# include "apple.h"
+
+# define ERROR(code, str) \
+ do { hfs_error = (str), errno = (code); goto fail; } while (0)
+
+# ifdef DEBUG
+# define ASSERT(cond) do { if (! (cond)) abort(); } while (0)
+# else
+# define ASSERT(cond) /* nothing */
+# endif
+
+# define SIZE(type, n) ((size_t) (sizeof(type) * (n)))
+# define ALLOC(type, n) ((type *) malloc(SIZE(type, n)))
+# define ALLOCX(type, n) ((n) ? ALLOC(type, n) : (type *) 0)
+# define FREE(ptr) ((ptr) ? (void) free((void *) ptr) : (void) 0)
+
+# define REALLOC(ptr, type, n) \
+ ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n))))
+# define REALLOCX(ptr, type, n) \
+ ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0))
+
+# define BMTST(bm, num) \
+ (((const byte *) (bm))[(num) >> 3] & (0x80 >> ((num) & 0x07)))
+# define BMSET(bm, num) \
+ (((byte *) (bm))[(num) >> 3] |= (0x80 >> ((num) & 0x07)))
+# define BMCLR(bm, num) \
+ (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07)))
+
+# define STRINGIZE(x) #x
+# define STR(x) STRINGIZE(x)
+
+typedef unsigned char byte;
+typedef byte block[HFS_BLOCKSZ];
+
+typedef struct _bucket_ {
+ int flags; /* bit flags */
+ unsigned int count; /* number of times this block is requested */
+
+ unsigned long bnum; /* logical block number */
+ block *data; /* pointer to block contents */
+
+ struct _bucket_ *cnext; /* next bucket in cache chain */
+ struct _bucket_ *cprev; /* previous bucket in cache chain */
+
+ struct _bucket_ *hnext; /* next bucket in hash chain */
+ struct _bucket_ **hprev; /* previous bucket's pointer to this bucket */
+} bucket;
+
+# define HFS_BUCKET_INUSE 0x01
+# define HFS_BUCKET_DIRTY 0x02
+
+# define HFS_CACHESZ 128
+# define HFS_HASHSZ 32
+# define HFS_BLOCKBUFSZ 16
+
+typedef struct {
+ struct _hfsvol_ *vol; /* volume to which cache belongs */
+ bucket *tail; /* end of bucket chain */
+
+ unsigned int hits; /* number of cache hits */
+ unsigned int misses; /* number of cache misses */
+
+ bucket chain[HFS_CACHESZ]; /* cache bucket chain */
+ bucket *hash[HFS_HASHSZ]; /* hash table for bucket chain */
+
+ block pool[HFS_CACHESZ]; /* physical blocks in cache */
+} bcache;
+
+# define HFS_MAP1SZ 256
+# define HFS_MAPXSZ 492
+
+# define HFS_NODEREC(nd, rnum) ((nd).data + (nd).roff[rnum])
+# define HFS_RECLEN(nd, rnum) ((nd).roff[(rnum) + 1] - (nd).roff[rnum])
+
+# define HFS_RECKEYLEN(ptr) (*(const byte *) (ptr))
+# define HFS_RECKEYSKIP(ptr) ((size_t) ((1 + HFS_RECKEYLEN(ptr) + 1) & ~1))
+# define HFS_RECDATA(ptr) ((ptr) + HFS_RECKEYSKIP(ptr))
+
+# define HFS_SETKEYLEN(ptr, x) (*(byte *) (ptr) = (x))
+
+# define HFS_CATDATALEN sizeof(CatDataRec)
+# define HFS_EXTDATALEN sizeof(ExtDataRec)
+# define HFS_MAX_DATALEN (HFS_CATDATALEN > HFS_EXTDATALEN ? \
+ HFS_CATDATALEN : HFS_EXTDATALEN)
+
+# define HFS_CATKEYLEN sizeof(CatKeyRec)
+# define HFS_EXTKEYLEN sizeof(ExtKeyRec)
+# define HFS_MAX_KEYLEN (HFS_CATKEYLEN > HFS_EXTKEYLEN ? \
+ HFS_CATKEYLEN : HFS_EXTKEYLEN)
+
+# define HFS_MAX_CATRECLEN (HFS_CATKEYLEN + HFS_CATDATALEN)
+# define HFS_MAX_EXTRECLEN (HFS_EXTKEYLEN + HFS_EXTDATALEN)
+# define HFS_MAX_RECLEN (HFS_MAX_KEYLEN + HFS_MAX_DATALEN)
+
+# define HFS_SIGWORD 0x4244
+# define HFS_SIGWORD_MFS ((Integer) 0xd2d7)
+
+# define HFS_ATRB_BUSY (1 << 6)
+# define HFS_ATRB_HLOCKED (1 << 7)
+# define HFS_ATRB_UMOUNTED (1 << 8)
+# define HFS_ATRB_BBSPARED (1 << 9)
+# define HFS_ATRB_BVINCONSIS (1 << 11)
+# define HFS_ATRB_COPYPROT (1 << 14)
+# define HFS_ATRB_SLOCKED (1 << 15)
+
+struct _hfsfile_ {
+ struct _hfsvol_ *vol; /* pointer to volume descriptor */
+ unsigned long parid; /* parent directory ID of this file */
+ char name[HFS_MAX_FLEN + 1]; /* catalog name of this file */
+ CatDataRec cat; /* catalog information */
+ ExtDataRec ext; /* current extent record */
+ unsigned int fabn; /* starting file allocation block number */
+ int fork; /* current selected fork for I/O */
+ unsigned long pos; /* current file seek pointer */
+ int flags; /* bit flags */
+
+ struct _hfsfile_ *prev;
+ struct _hfsfile_ *next;
+};
+
+# define HFS_FILE_UPDATE_CATREC 0x01
+
+# define HFS_MAX_NRECS 35 /* maximum based on minimum record size */
+
+typedef struct _node_ {
+ struct _btree_ *bt; /* btree to which this node belongs */
+ unsigned long nnum; /* node index */
+ NodeDescriptor nd; /* node descriptor */
+ int rnum; /* current record index */
+ UInteger roff[HFS_MAX_NRECS + 1];
+ /* record offsets */
+ block data; /* raw contents of node */
+} node;
+
+struct _hfsdir_ {
+ struct _hfsvol_ *vol; /* associated volume */
+ unsigned long dirid; /* directory ID of interest (or 0) */
+
+ node n; /* current B*-tree node */
+ struct _hfsvol_ *vptr; /* current volume pointer */
+
+ struct _hfsdir_ *prev;
+ struct _hfsdir_ *next;
+};
+
+typedef void (*keyunpackfunc)(const byte *, void *);
+typedef int (*keycomparefunc)(const void *, const void *);
+
+typedef struct _btree_ {
+ hfsfile f; /* subset file information */
+ node hdrnd; /* header node */
+ BTHdrRec hdr; /* header record */
+ byte *map; /* usage bitmap */
+ unsigned long mapsz; /* number of bytes in bitmap */
+ int flags; /* bit flags */
+
+ keyunpackfunc keyunpack; /* key unpacking function */
+ keycomparefunc keycompare; /* key comparison function */
+} btree;
+
+# define HFS_BT_UPDATE_HDR 0x01
+
+struct _hfsvol_ {
+ int os_fd; /* OS-dependent private descriptor data */
+ int flags; /* bit flags */
+
+ int pnum; /* ordinal HFS partition number */
+ unsigned long vstart; /* logical block offset to start of volume */
+ unsigned long vlen; /* number of logical blocks in volume */
+ unsigned int lpa; /* number of logical blocks per allocation block */
+
+ bcache *cache; /* cache of recently used blocks */
+
+ MDB mdb; /* master directory block */
+ block *vbm; /* volume bitmap */
+ unsigned short vbmsz; /* number of blocks in bitmap */
+
+ btree ext; /* B*-tree control block for extents overflow file */
+ btree cat; /* B*-tree control block for catalog file */
+
+ unsigned long cwd; /* directory id of current working directory */
+
+ int refs; /* number of external references to this volume */
+ hfsfile *files; /* list of open files */
+ hfsdir *dirs; /* list of open directories */
+
+ struct _hfsvol_ *prev;
+ struct _hfsvol_ *next;
+};
+
+# define HFS_VOL_OPEN 0x0001
+# define HFS_VOL_MOUNTED 0x0002
+# define HFS_VOL_READONLY 0x0004
+# define HFS_VOL_USINGCACHE 0x0008
+
+# define HFS_VOL_UPDATE_MDB 0x0010
+# define HFS_VOL_UPDATE_ALTMDB 0x0020
+# define HFS_VOL_UPDATE_VBM 0x0040
+
+# define HFS_VOL_OPT_MASK 0xff00
+
+extern hfsvol *hfs_mounts;
diff --git a/qemu/roms/openbios/fs/hfs/include/low.h b/qemu/roms/openbios/fs/hfs/include/low.h
new file mode 100644
index 000000000..56d049a8e
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/low.h
@@ -0,0 +1,45 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: low.h,v 1.6 1998/04/11 08:27:13 rob Exp $
+ */
+
+# define HFS_DDR_SIGWORD 0x4552
+
+# define HFS_PM_SIGWORD 0x504d
+# define HFS_PM_SIGWORD_OLD 0x5453
+
+# define HFS_BB_SIGWORD 0x4c4b
+
+# define HFS_BOOTCODE1LEN (HFS_BLOCKSZ - 148)
+# define HFS_BOOTCODE2LEN HFS_BLOCKSZ
+
+# define HFS_BOOTCODELEN (HFS_BOOTCODE1LEN + HFS_BOOTCODE2LEN)
+
+int l_getddr(hfsvol *, Block0 *);
+int l_putddr(hfsvol *, const Block0 *);
+
+int l_getpmentry(hfsvol *, Partition *, unsigned long);
+int l_putpmentry(hfsvol *, const Partition *, unsigned long);
+
+int l_getbb(hfsvol *, BootBlkHdr *, byte *);
+int l_putbb(hfsvol *, const BootBlkHdr *, const byte *);
+
+int l_getmdb(hfsvol *, MDB *, int);
+int l_putmdb(hfsvol *, const MDB *, int);
diff --git a/qemu/roms/openbios/fs/hfs/include/medium.h b/qemu/roms/openbios/fs/hfs/include/medium.h
new file mode 100644
index 000000000..29d97a4e7
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/medium.h
@@ -0,0 +1,43 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: medium.h,v 1.3 1998/04/11 08:27:13 rob Exp $
+ */
+
+/*
+ * Partition Types:
+ *
+ * "Apple_partition_map" partition map
+ * "Apple_Driver" device driver
+ * "Apple_Driver43" SCSI Manager 4.3 device driver
+ * "Apple_MFS" Macintosh 64K ROM filesystem
+ * "Apple_HFS" Macintosh hierarchical filesystem
+ * "Apple_Unix_SVR2" Unix filesystem
+ * "Apple_PRODOS" ProDOS filesystem
+ * "Apple_Free" unused
+ * "Apple_Scratch" empty
+ */
+
+int m_zeroddr(hfsvol *);
+
+int m_zeropm(hfsvol *, unsigned int);
+int m_findpmentry(hfsvol *, const char *, Partition *, unsigned long *);
+int m_mkpart(hfsvol *, const char *, const char *, unsigned long);
+
+int m_zerobb(hfsvol *);
diff --git a/qemu/roms/openbios/fs/hfs/include/node.h b/qemu/roms/openbios/fs/hfs/include/node.h
new file mode 100644
index 000000000..d7367fd57
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/node.h
@@ -0,0 +1,35 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: node.h,v 1.7 1998/11/02 22:09:06 rob Exp $
+ */
+
+void n_init(node *, btree *, int, int);
+
+int n_new(node *);
+int n_free(node *);
+
+int n_search(node *, const byte *);
+
+void n_index(const node *, byte *, unsigned int *);
+
+void n_insertx(node *, const byte *, unsigned int);
+int n_insert(node *, byte *, unsigned int *);
+
+int n_delete(node *, byte *, int *);
diff --git a/qemu/roms/openbios/fs/hfs/include/record.h b/qemu/roms/openbios/fs/hfs/include/record.h
new file mode 100644
index 000000000..283e809fa
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/record.h
@@ -0,0 +1,48 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: record.h,v 1.7 1998/11/02 22:09:08 rob Exp $
+ */
+
+void r_packcatkey(const CatKeyRec *, byte *, unsigned int *);
+void r_unpackcatkey(const byte *, CatKeyRec *);
+
+void r_packextkey(const ExtKeyRec *, byte *, unsigned int *);
+void r_unpackextkey(const byte *, ExtKeyRec *);
+
+int r_comparecatkeys(const CatKeyRec *, const CatKeyRec *);
+int r_compareextkeys(const ExtKeyRec *, const ExtKeyRec *);
+
+void r_packcatdata(const CatDataRec *, byte *, unsigned int *);
+void r_unpackcatdata(const byte *, CatDataRec *);
+
+void r_packextdata(const ExtDataRec *, byte *, unsigned int *);
+void r_unpackextdata(const byte *, ExtDataRec *);
+
+void r_makecatkey(CatKeyRec *, unsigned long, const char *);
+void r_makeextkey(ExtKeyRec *, int, unsigned long, unsigned int);
+
+void r_packcatrec(const CatKeyRec *, const CatDataRec *,
+ byte *, unsigned int *);
+void r_packextrec(const ExtKeyRec *, const ExtDataRec *,
+ byte *, unsigned int *);
+
+void r_packdirent(CatDataRec *, const hfsdirent *);
+void r_unpackdirent(unsigned long, const char *,
+ const CatDataRec *, hfsdirent *);
diff --git a/qemu/roms/openbios/fs/hfs/include/volume.h b/qemu/roms/openbios/fs/hfs/include/volume.h
new file mode 100644
index 000000000..562c2d194
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/include/volume.h
@@ -0,0 +1,71 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: volume.h,v 1.7 1998/11/02 22:09:12 rob Exp $
+ */
+
+#ifndef _H_VOLUME
+#define _H_VOLUME
+
+void v_init(hfsvol *, int);
+
+int v_open(hfsvol *, int os_fd);
+int v_flush(hfsvol *);
+int v_close(hfsvol *);
+
+int v_same(hfsvol *, int os_fd);
+int v_geometry(hfsvol *, int);
+
+int v_readmdb(hfsvol *);
+int v_writemdb(hfsvol *);
+
+int v_readvbm(hfsvol *);
+int v_writevbm(hfsvol *);
+
+int v_mount(hfsvol *);
+int v_dirty(hfsvol *);
+
+int v_catsearch(hfsvol *, unsigned long, const char *,
+ CatDataRec *, char *, node *);
+int v_extsearch(hfsfile *, unsigned int, ExtDataRec *, node *);
+
+int v_getthread(hfsvol *, unsigned long, CatDataRec *, node *, int);
+
+# define v_getdthread(vol, id, thread, np) \
+ v_getthread(vol, id, thread, np, cdrThdRec)
+# define v_getfthread(vol, id, thread, np) \
+ v_getthread(vol, id, thread, np, cdrFThdRec)
+
+int v_putcatrec(const CatDataRec *, node *);
+int v_putextrec(const ExtDataRec *, node *);
+
+int v_allocblocks(hfsvol *, ExtDescriptor *);
+int v_freeblocks(hfsvol *, const ExtDescriptor *);
+
+int v_resolve(hfsvol **vol, const char *path,
+ CatDataRec *data, unsigned long *parid, char *fname, node *np);
+
+int v_adjvalence(hfsvol *, unsigned long, int, int);
+int v_mkdir(hfsvol *, unsigned long, const char *);
+
+int v_scavenge(hfsvol *);
+
+int v_probe(int fd, long long offset);
+
+#endif /* _H_VOLUME */
diff --git a/qemu/roms/openbios/fs/hfs/low.c b/qemu/roms/openbios/fs/hfs/low.c
new file mode 100644
index 000000000..e0f7cb0e3
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/low.c
@@ -0,0 +1,157 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998, 2001 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: low.c,v 1.8 1998/11/02 22:09:03 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "low.h"
+#include "data.h"
+#include "block.h"
+#include "file.h"
+
+/*
+ * NAME: low->getpmentry()
+ * DESCRIPTION: read a partition map entry
+ */
+int l_getpmentry(hfsvol *vol, Partition *map, unsigned long bnum)
+{
+ block b;
+ const byte *ptr = b;
+ int i;
+
+ if (b_readpb(vol, bnum, &b, 1) == -1)
+ goto fail;
+
+ d_fetchsw(&ptr, &map->pmSig);
+ d_fetchsw(&ptr, &map->pmSigPad);
+ d_fetchsl(&ptr, &map->pmMapBlkCnt);
+ d_fetchsl(&ptr, &map->pmPyPartStart);
+ d_fetchsl(&ptr, &map->pmPartBlkCnt);
+
+ strncpy((char *) map->pmPartName, (const char *) ptr, 32);
+ map->pmPartName[32] = 0;
+ ptr += 32;
+
+ strncpy((char *) map->pmParType, (const char *) ptr, 32);
+ map->pmParType[32] = 0;
+ ptr += 32;
+
+ d_fetchsl(&ptr, &map->pmLgDataStart);
+ d_fetchsl(&ptr, &map->pmDataCnt);
+ d_fetchsl(&ptr, &map->pmPartStatus);
+ d_fetchsl(&ptr, &map->pmLgBootStart);
+ d_fetchsl(&ptr, &map->pmBootSize);
+ d_fetchsl(&ptr, &map->pmBootAddr);
+ d_fetchsl(&ptr, &map->pmBootAddr2);
+ d_fetchsl(&ptr, &map->pmBootEntry);
+ d_fetchsl(&ptr, &map->pmBootEntry2);
+ d_fetchsl(&ptr, &map->pmBootCksum);
+
+ strncpy((char *) map->pmProcessor, (const char *) ptr, 16);
+ map->pmProcessor[16] = 0;
+ ptr += 16;
+
+ for (i = 0; i < 188; ++i)
+ d_fetchsw(&ptr, &map->pmPad[i]);
+
+ ASSERT(ptr - b == HFS_BLOCKSZ);
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: low->getmdb()
+ * DESCRIPTION: read a master directory block
+ */
+int l_getmdb(hfsvol *vol, MDB *mdb, int backup)
+{
+ block b;
+ const byte *ptr = b;
+ int i;
+
+ if (b_readlb(vol, backup ? vol->vlen - 2 : 2, &b) == -1)
+ goto fail;
+
+ d_fetchsw(&ptr, &mdb->drSigWord);
+ d_fetchsl(&ptr, &mdb->drCrDate);
+ d_fetchsl(&ptr, &mdb->drLsMod);
+ d_fetchsw(&ptr, &mdb->drAtrb);
+ d_fetchuw(&ptr, &mdb->drNmFls);
+ d_fetchuw(&ptr, &mdb->drVBMSt);
+ d_fetchuw(&ptr, &mdb->drAllocPtr);
+ d_fetchuw(&ptr, &mdb->drNmAlBlks);
+ d_fetchul(&ptr, &mdb->drAlBlkSiz);
+ d_fetchul(&ptr, &mdb->drClpSiz);
+ d_fetchuw(&ptr, &mdb->drAlBlSt);
+ d_fetchsl(&ptr, &mdb->drNxtCNID);
+ d_fetchuw(&ptr, &mdb->drFreeBks);
+
+ d_fetchstr(&ptr, mdb->drVN, sizeof(mdb->drVN));
+
+ ASSERT(ptr - b == 64);
+
+ d_fetchsl(&ptr, &mdb->drVolBkUp);
+ d_fetchsw(&ptr, &mdb->drVSeqNum);
+ d_fetchul(&ptr, &mdb->drWrCnt);
+ d_fetchul(&ptr, &mdb->drXTClpSiz);
+ d_fetchul(&ptr, &mdb->drCTClpSiz);
+ d_fetchuw(&ptr, &mdb->drNmRtDirs);
+ d_fetchul(&ptr, &mdb->drFilCnt);
+ d_fetchul(&ptr, &mdb->drDirCnt);
+
+ for (i = 0; i < 8; ++i)
+ d_fetchsl(&ptr, &mdb->drFndrInfo[i]);
+
+ ASSERT(ptr - b == 124);
+
+ d_fetchuw(&ptr, &mdb->drEmbedSigWord);
+ d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrStABN);
+ d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrNumABlks);
+
+ d_fetchul(&ptr, &mdb->drXTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrStABN);
+ d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrNumABlks);
+ }
+
+ ASSERT(ptr - b == 146);
+
+ d_fetchul(&ptr, &mdb->drCTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrStABN);
+ d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrNumABlks);
+ }
+
+ ASSERT(ptr - b == 162);
+
+ return 0;
+
+fail:
+ return -1;
+}
diff --git a/qemu/roms/openbios/fs/hfs/medium.c b/qemu/roms/openbios/fs/hfs/medium.c
new file mode 100644
index 000000000..171ba80dc
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/medium.c
@@ -0,0 +1,84 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: medium.c,v 1.4 1998/11/02 22:09:04 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "block.h"
+#include "low.h"
+#include "medium.h"
+
+
+/*
+ * NAME: medium->findpmentry()
+ * DESCRIPTION: locate a partition map entry
+ */
+int m_findpmentry(hfsvol *vol, const char *type,
+ Partition *map, unsigned long *start)
+{
+ unsigned long bnum;
+ int found = 0;
+
+ if (start && *start > 0)
+ {
+ bnum = *start;
+
+ if (bnum++ >= (unsigned long) map->pmMapBlkCnt)
+ ERROR(EINVAL, "partition not found");
+ }
+ else
+ bnum = 1;
+
+ while (1)
+ {
+ if (l_getpmentry(vol, map, bnum) == -1)
+ {
+ found = -1;
+ goto fail;
+ }
+
+ if (map->pmSig != HFS_PM_SIGWORD)
+ {
+ found = -1;
+
+ if (map->pmSig == HFS_PM_SIGWORD_OLD)
+ ERROR(EINVAL, "old partition map format not supported");
+ else
+ ERROR(EINVAL, "invalid partition map");
+ }
+
+ if (strcmp((char *) map->pmParType, type) == 0)
+ {
+ found = 1;
+ goto done;
+ }
+
+ if (bnum++ >= (unsigned long) map->pmMapBlkCnt)
+ ERROR(EINVAL, "partition not found");
+ }
+
+done:
+ if (start)
+ *start = bnum;
+
+fail:
+ return found;
+}
diff --git a/qemu/roms/openbios/fs/hfs/node.c b/qemu/roms/openbios/fs/hfs/node.c
new file mode 100644
index 000000000..1670f038b
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/node.c
@@ -0,0 +1,60 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: node.c,v 1.9 1998/11/02 22:09:05 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "node.h"
+#include "data.h"
+#include "btree.h"
+
+/*
+ * NAME: node->search()
+ * DESCRIPTION: locate a record in a node, or the record it should follow
+ */
+int n_search(node *np, const byte *pkey)
+{
+ const btree *bt = np->bt;
+ byte key1[HFS_MAX_KEYLEN], key2[HFS_MAX_KEYLEN];
+ int i, comp = -1;
+
+ bt->keyunpack(pkey, key2);
+
+ for (i = np->nd.ndNRecs; i--; )
+ {
+ const byte *rec;
+
+ rec = HFS_NODEREC(*np, i);
+
+ if (HFS_RECKEYLEN(rec) == 0)
+ continue; /* deleted record */
+
+ bt->keyunpack(rec, key1);
+ comp = bt->keycompare(key1, key2);
+
+ if (comp <= 0)
+ break;
+ }
+
+ np->rnum = i;
+
+ return comp == 0;
+}
diff --git a/qemu/roms/openbios/fs/hfs/record.c b/qemu/roms/openbios/fs/hfs/record.c
new file mode 100644
index 000000000..92a3adddf
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/record.c
@@ -0,0 +1,553 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: record.c,v 1.9 1998/11/02 22:09:07 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "record.h"
+#include "data.h"
+
+/*
+ * NAME: record->packcatkey()
+ * DESCRIPTION: pack a catalog record key
+ */
+void r_packcatkey(const CatKeyRec *key, byte *pkey, unsigned int *len)
+{
+ const byte *start = pkey;
+
+ d_storesb(&pkey, key->ckrKeyLen);
+ d_storesb(&pkey, key->ckrResrv1);
+ d_storeul(&pkey, key->ckrParID);
+
+ d_storestr(&pkey, key->ckrCName, sizeof(key->ckrCName));
+
+ if (len)
+ *len = HFS_RECKEYSKIP(start);
+}
+
+/*
+ * NAME: record->unpackcatkey()
+ * DESCRIPTION: unpack a catalog record key
+ */
+void r_unpackcatkey(const byte *pkey, CatKeyRec *key)
+{
+ d_fetchsb(&pkey, &key->ckrKeyLen);
+ d_fetchsb(&pkey, &key->ckrResrv1);
+ d_fetchul(&pkey, &key->ckrParID);
+
+ d_fetchstr(&pkey, key->ckrCName, sizeof(key->ckrCName));
+}
+
+/*
+ * NAME: record->packextkey()
+ * DESCRIPTION: pack an extents record key
+ */
+void r_packextkey(const ExtKeyRec *key, byte *pkey, unsigned int *len)
+{
+ const byte *start = pkey;
+
+ d_storesb(&pkey, key->xkrKeyLen);
+ d_storesb(&pkey, key->xkrFkType);
+ d_storeul(&pkey, key->xkrFNum);
+ d_storeuw(&pkey, key->xkrFABN);
+
+ if (len)
+ *len = HFS_RECKEYSKIP(start);
+}
+
+/*
+ * NAME: record->unpackextkey()
+ * DESCRIPTION: unpack an extents record key
+ */
+void r_unpackextkey(const byte *pkey, ExtKeyRec *key)
+{
+ d_fetchsb(&pkey, &key->xkrKeyLen);
+ d_fetchsb(&pkey, &key->xkrFkType);
+ d_fetchul(&pkey, &key->xkrFNum);
+ d_fetchuw(&pkey, &key->xkrFABN);
+}
+
+/*
+ * NAME: record->comparecatkeys()
+ * DESCRIPTION: compare two (packed) catalog record keys
+ */
+int r_comparecatkeys(const CatKeyRec *key1, const CatKeyRec *key2)
+{
+ int diff;
+
+ diff = key1->ckrParID - key2->ckrParID;
+ if (diff)
+ return diff;
+
+ return d_relstring(key1->ckrCName, key2->ckrCName);
+}
+
+/*
+ * NAME: record->compareextkeys()
+ * DESCRIPTION: compare two (packed) extents record keys
+ */
+int r_compareextkeys(const ExtKeyRec *key1, const ExtKeyRec *key2)
+{
+ int diff;
+
+ diff = key1->xkrFNum - key2->xkrFNum;
+ if (diff)
+ return diff;
+
+ diff = (unsigned char) key1->xkrFkType -
+ (unsigned char) key2->xkrFkType;
+ if (diff)
+ return diff;
+
+ return key1->xkrFABN - key2->xkrFABN;
+}
+
+/*
+ * NAME: record->packcatdata()
+ * DESCRIPTION: pack catalog record data
+ */
+void r_packcatdata(const CatDataRec *data, byte *pdata, unsigned int *len)
+{
+ const byte *start = pdata;
+ int i;
+
+ d_storesb(&pdata, data->cdrType);
+ d_storesb(&pdata, data->cdrResrv2);
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ d_storesw(&pdata, data->u.dir.dirFlags);
+ d_storeuw(&pdata, data->u.dir.dirVal);
+ d_storeul(&pdata, data->u.dir.dirDirID);
+ d_storesl(&pdata, data->u.dir.dirCrDat);
+ d_storesl(&pdata, data->u.dir.dirMdDat);
+ d_storesl(&pdata, data->u.dir.dirBkDat);
+
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.top);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.left);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.bottom);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.right);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frFlags);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.v);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.h);
+ d_storesw(&pdata, data->u.dir.dirUsrInfo.frView);
+
+ d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.v);
+ d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.h);
+ d_storesl(&pdata, data->u.dir.dirFndrInfo.frOpenChain);
+ d_storesw(&pdata, data->u.dir.dirFndrInfo.frUnused);
+ d_storesw(&pdata, data->u.dir.dirFndrInfo.frComment);
+ d_storesl(&pdata, data->u.dir.dirFndrInfo.frPutAway);
+
+ for (i = 0; i < 4; ++i)
+ d_storesl(&pdata, data->u.dir.dirResrv[i]);
+
+ break;
+
+ case cdrFilRec:
+ d_storesb(&pdata, data->u.fil.filFlags);
+ d_storesb(&pdata, data->u.fil.filTyp);
+
+ d_storesl(&pdata, data->u.fil.filUsrWds.fdType);
+ d_storesl(&pdata, data->u.fil.filUsrWds.fdCreator);
+ d_storesw(&pdata, data->u.fil.filUsrWds.fdFlags);
+ d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.v);
+ d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.h);
+ d_storesw(&pdata, data->u.fil.filUsrWds.fdFldr);
+
+ d_storeul(&pdata, data->u.fil.filFlNum);
+
+ d_storeuw(&pdata, data->u.fil.filStBlk);
+ d_storeul(&pdata, data->u.fil.filLgLen);
+ d_storeul(&pdata, data->u.fil.filPyLen);
+
+ d_storeuw(&pdata, data->u.fil.filRStBlk);
+ d_storeul(&pdata, data->u.fil.filRLgLen);
+ d_storeul(&pdata, data->u.fil.filRPyLen);
+
+ d_storesl(&pdata, data->u.fil.filCrDat);
+ d_storesl(&pdata, data->u.fil.filMdDat);
+ d_storesl(&pdata, data->u.fil.filBkDat);
+
+ d_storesw(&pdata, data->u.fil.filFndrInfo.fdIconID);
+ for (i = 0; i < 4; ++i)
+ d_storesw(&pdata, data->u.fil.filFndrInfo.fdUnused[i]);
+ d_storesw(&pdata, data->u.fil.filFndrInfo.fdComment);
+ d_storesl(&pdata, data->u.fil.filFndrInfo.fdPutAway);
+
+ d_storeuw(&pdata, data->u.fil.filClpSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrStABN);
+ d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrNumABlks);
+ }
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrStABN);
+ d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks);
+ }
+
+ d_storesl(&pdata, data->u.fil.filResrv);
+
+ break;
+
+ case cdrThdRec:
+ for (i = 0; i < 2; ++i)
+ d_storesl(&pdata, data->u.dthd.thdResrv[i]);
+
+ d_storeul(&pdata, data->u.dthd.thdParID);
+
+ d_storestr(&pdata, data->u.dthd.thdCName,
+ sizeof(data->u.dthd.thdCName));
+
+ break;
+
+ case cdrFThdRec:
+ for (i = 0; i < 2; ++i)
+ d_storesl(&pdata, data->u.fthd.fthdResrv[i]);
+
+ d_storeul(&pdata, data->u.fthd.fthdParID);
+
+ d_storestr(&pdata, data->u.fthd.fthdCName,
+ sizeof(data->u.fthd.fthdCName));
+
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+ if (len)
+ *len += pdata - start;
+}
+
+/*
+ * NAME: record->unpackcatdata()
+ * DESCRIPTION: unpack catalog record data
+ */
+void r_unpackcatdata(const byte *pdata, CatDataRec *data)
+{
+ int i;
+
+ d_fetchsb(&pdata, &data->cdrType);
+ d_fetchsb(&pdata, &data->cdrResrv2);
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ d_fetchsw(&pdata, &data->u.dir.dirFlags);
+ d_fetchuw(&pdata, &data->u.dir.dirVal);
+ d_fetchul(&pdata, &data->u.dir.dirDirID);
+ d_fetchsl(&pdata, &data->u.dir.dirCrDat);
+ d_fetchsl(&pdata, &data->u.dir.dirMdDat);
+ d_fetchsl(&pdata, &data->u.dir.dirBkDat);
+
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.top);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.left);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.right);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frFlags);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h);
+ d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frView);
+
+ d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v);
+ d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h);
+ d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain);
+ d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frUnused);
+ d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frComment);
+ d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frPutAway);
+
+ for (i = 0; i < 4; ++i)
+ d_fetchsl(&pdata, &data->u.dir.dirResrv[i]);
+
+ break;
+
+ case cdrFilRec:
+ d_fetchsb(&pdata, &data->u.fil.filFlags);
+ d_fetchsb(&pdata, &data->u.fil.filTyp);
+
+ d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdType);
+ d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdCreator);
+ d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFlags);
+ d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.v);
+ d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.h);
+ d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFldr);
+
+ d_fetchul(&pdata, &data->u.fil.filFlNum);
+
+ d_fetchuw(&pdata, &data->u.fil.filStBlk);
+ d_fetchul(&pdata, &data->u.fil.filLgLen);
+ d_fetchul(&pdata, &data->u.fil.filPyLen);
+
+ d_fetchuw(&pdata, &data->u.fil.filRStBlk);
+ d_fetchul(&pdata, &data->u.fil.filRLgLen);
+ d_fetchul(&pdata, &data->u.fil.filRPyLen);
+
+ d_fetchsl(&pdata, &data->u.fil.filCrDat);
+ d_fetchsl(&pdata, &data->u.fil.filMdDat);
+ d_fetchsl(&pdata, &data->u.fil.filBkDat);
+
+ d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdIconID);
+ for (i = 0; i < 4; ++i)
+ d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]);
+ d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdComment);
+ d_fetchsl(&pdata, &data->u.fil.filFndrInfo.fdPutAway);
+
+ d_fetchuw(&pdata, &data->u.fil.filClpSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrStABN);
+ d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrNumABlks);
+ }
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrStABN);
+ d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrNumABlks);
+ }
+
+ d_fetchsl(&pdata, &data->u.fil.filResrv);
+
+ break;
+
+ case cdrThdRec:
+ for (i = 0; i < 2; ++i)
+ d_fetchsl(&pdata, &data->u.dthd.thdResrv[i]);
+
+ d_fetchul(&pdata, &data->u.dthd.thdParID);
+
+ d_fetchstr(&pdata, data->u.dthd.thdCName,
+ sizeof(data->u.dthd.thdCName));
+
+ break;
+
+ case cdrFThdRec:
+ for (i = 0; i < 2; ++i)
+ d_fetchsl(&pdata, &data->u.fthd.fthdResrv[i]);
+
+ d_fetchul(&pdata, &data->u.fthd.fthdParID);
+
+ d_fetchstr(&pdata, data->u.fthd.fthdCName,
+ sizeof(data->u.fthd.fthdCName));
+
+ break;
+
+ default:
+ ASSERT(0);
+ }
+}
+
+/*
+ * NAME: record->packextdata()
+ * DESCRIPTION: pack extent record data
+ */
+void r_packextdata(const ExtDataRec *data, byte *pdata, unsigned int *len)
+{
+ const byte *start = pdata;
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storeuw(&pdata, (*data)[i].xdrStABN);
+ d_storeuw(&pdata, (*data)[i].xdrNumABlks);
+ }
+
+ if (len)
+ *len += pdata - start;
+}
+
+/*
+ * NAME: record->unpackextdata()
+ * DESCRIPTION: unpack extent record data
+ */
+void r_unpackextdata(const byte *pdata, ExtDataRec *data)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchuw(&pdata, &(*data)[i].xdrStABN);
+ d_fetchuw(&pdata, &(*data)[i].xdrNumABlks);
+ }
+}
+
+/*
+ * NAME: record->makecatkey()
+ * DESCRIPTION: construct a catalog record key
+ */
+void r_makecatkey(CatKeyRec *key, unsigned long parid, const char *name)
+{
+ int len;
+
+ len = strlen(name) + 1;
+
+ key->ckrKeyLen = 0x05 + len + (len & 1);
+ key->ckrResrv1 = 0;
+ key->ckrParID = parid;
+
+ strcpy(key->ckrCName, name);
+}
+
+/*
+ * NAME: record->makeextkey()
+ * DESCRIPTION: construct an extents record key
+ */
+void r_makeextkey(ExtKeyRec *key,
+ int fork, unsigned long fnum, unsigned int fabn)
+{
+ key->xkrKeyLen = 0x07;
+ key->xkrFkType = fork;
+ key->xkrFNum = fnum;
+ key->xkrFABN = fabn;
+}
+
+/*
+ * NAME: record->packcatrec()
+ * DESCRIPTION: create a packed catalog record
+ */
+void r_packcatrec(const CatKeyRec *key, const CatDataRec *data,
+ byte *precord, unsigned int *len)
+{
+ r_packcatkey(key, precord, len);
+ r_packcatdata(data, HFS_RECDATA(precord), len);
+}
+
+/*
+ * NAME: record->packextrec()
+ * DESCRIPTION: create a packed extents record
+ */
+void r_packextrec(const ExtKeyRec *key, const ExtDataRec *data,
+ byte *precord, unsigned int *len)
+{
+ r_packextkey(key, precord, len);
+ r_packextdata(data, HFS_RECDATA(precord), len);
+}
+
+/*
+ * NAME: record->packdirent()
+ * DESCRIPTION: make changes to a catalog record
+ */
+void r_packdirent(CatDataRec *data, const hfsdirent *ent)
+{
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ data->u.dir.dirCrDat = d_mtime(ent->crdate);
+ data->u.dir.dirMdDat = d_mtime(ent->mddate);
+ data->u.dir.dirBkDat = d_mtime(ent->bkdate);
+
+ data->u.dir.dirUsrInfo.frFlags = ent->fdflags;
+ data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v;
+ data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h;
+
+ data->u.dir.dirUsrInfo.frRect.top = ent->u.dir.rect.top;
+ data->u.dir.dirUsrInfo.frRect.left = ent->u.dir.rect.left;
+ data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom;
+ data->u.dir.dirUsrInfo.frRect.right = ent->u.dir.rect.right;
+
+ break;
+
+ case cdrFilRec:
+ if (ent->flags & HFS_ISLOCKED)
+ data->u.fil.filFlags |= (1 << 0);
+ else
+ data->u.fil.filFlags &= ~(1 << 0);
+
+ data->u.fil.filCrDat = d_mtime(ent->crdate);
+ data->u.fil.filMdDat = d_mtime(ent->mddate);
+ data->u.fil.filBkDat = d_mtime(ent->bkdate);
+
+ data->u.fil.filUsrWds.fdFlags = ent->fdflags;
+ data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v;
+ data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h;
+
+ data->u.fil.filUsrWds.fdType =
+ d_getsl((const unsigned char *) ent->u.file.type);
+ data->u.fil.filUsrWds.fdCreator =
+ d_getsl((const unsigned char *) ent->u.file.creator);
+
+ break;
+ }
+}
+
+/*
+ * NAME: record->unpackdirent()
+ * DESCRIPTION: unpack catalog information into hfsdirent structure
+ */
+void r_unpackdirent(unsigned long parid, const char *name,
+ const CatDataRec *data, hfsdirent *ent)
+{
+ strcpy(ent->name, name);
+ ent->parid = parid;
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ ent->flags = HFS_ISDIR;
+ ent->cnid = data->u.dir.dirDirID;
+
+ ent->crdate = d_ltime(data->u.dir.dirCrDat);
+ ent->mddate = d_ltime(data->u.dir.dirMdDat);
+ ent->bkdate = d_ltime(data->u.dir.dirBkDat);
+
+ ent->fdflags = data->u.dir.dirUsrInfo.frFlags;
+ ent->fdlocation.v = data->u.dir.dirUsrInfo.frLocation.v;
+ ent->fdlocation.h = data->u.dir.dirUsrInfo.frLocation.h;
+
+ ent->u.dir.valence = data->u.dir.dirVal;
+
+ ent->u.dir.rect.top = data->u.dir.dirUsrInfo.frRect.top;
+ ent->u.dir.rect.left = data->u.dir.dirUsrInfo.frRect.left;
+ ent->u.dir.rect.bottom = data->u.dir.dirUsrInfo.frRect.bottom;
+ ent->u.dir.rect.right = data->u.dir.dirUsrInfo.frRect.right;
+
+ break;
+
+ case cdrFilRec:
+ ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0;
+ ent->cnid = data->u.fil.filFlNum;
+
+ ent->crdate = d_ltime(data->u.fil.filCrDat);
+ ent->mddate = d_ltime(data->u.fil.filMdDat);
+ ent->bkdate = d_ltime(data->u.fil.filBkDat);
+
+ ent->fdflags = data->u.fil.filUsrWds.fdFlags;
+ ent->fdlocation.v = data->u.fil.filUsrWds.fdLocation.v;
+ ent->fdlocation.h = data->u.fil.filUsrWds.fdLocation.h;
+
+ ent->u.file.dsize = data->u.fil.filLgLen;
+ ent->u.file.rsize = data->u.fil.filRLgLen;
+
+ d_putsl((unsigned char *) ent->u.file.type,
+ data->u.fil.filUsrWds.fdType);
+ d_putsl((unsigned char *) ent->u.file.creator,
+ data->u.fil.filUsrWds.fdCreator);
+
+ ent->u.file.type[4] = ent->u.file.creator[4] = 0;
+
+ break;
+ }
+}
diff --git a/qemu/roms/openbios/fs/hfs/volume.c b/qemu/roms/openbios/fs/hfs/volume.c
new file mode 100644
index 000000000..4faf7e6c2
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/volume.c
@@ -0,0 +1,612 @@
+/*
+ * libhfs - library for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996-1998 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * $Id: volume.c,v 1.12 1998/11/02 22:09:10 rob Exp $
+ */
+
+#include "config.h"
+#include "libhfs.h"
+#include "volume.h"
+#include "data.h"
+#include "block.h"
+#include "low.h"
+#include "medium.h"
+#include "file.h"
+#include "btree.h"
+#include "record.h"
+#include "os.h"
+
+#include "libc/byteorder.h"
+
+/*
+ * NAME: vol->init()
+ * DESCRIPTION: initialize volume structure
+ */
+void v_init(hfsvol *vol, int flags)
+{
+ btree *ext = &vol->ext;
+ btree *cat = &vol->cat;
+
+ vol->os_fd = 0;
+ vol->flags = flags & HFS_VOL_OPT_MASK;
+
+ vol->pnum = -1;
+ vol->vstart = 0;
+ vol->vlen = 0;
+ vol->lpa = 0;
+
+ vol->cache = NULL;
+
+ vol->vbm = NULL;
+ vol->vbmsz = 0;
+
+ f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow");
+
+ ext->map = NULL;
+ ext->mapsz = 0;
+ ext->flags = 0;
+
+ ext->keyunpack = (keyunpackfunc) r_unpackextkey;
+ ext->keycompare = (keycomparefunc) r_compareextkeys;
+
+ f_init(&cat->f, vol, HFS_CNID_CAT, "catalog");
+
+ cat->map = NULL;
+ cat->mapsz = 0;
+ cat->flags = 0;
+
+ cat->keyunpack = (keyunpackfunc) r_unpackcatkey;
+ cat->keycompare = (keycomparefunc) r_comparecatkeys;
+
+ vol->cwd = HFS_CNID_ROOTDIR;
+
+ vol->refs = 0;
+ vol->files = NULL;
+ vol->dirs = NULL;
+
+ vol->prev = NULL;
+ vol->next = NULL;
+}
+
+/*
+ * NAME: vol->open()
+ * DESCRIPTION: open volume source and lock against concurrent updates
+ */
+int v_open(hfsvol *vol, int os_fd )
+{
+ if (vol->flags & HFS_VOL_OPEN)
+ ERROR(EINVAL, "volume already open");
+
+ vol->flags |= HFS_VOL_OPEN;
+ vol->os_fd = os_fd;
+
+ /* initialize volume block cache (OK to fail) */
+
+ if (! (vol->flags & HFS_OPT_NOCACHE) &&
+ b_init(vol) != -1)
+ vol->flags |= HFS_VOL_USINGCACHE;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: vol->close()
+ * DESCRIPTION: close access path to volume source
+ */
+int v_close(hfsvol *vol)
+{
+ int result = 0;
+
+ if (! (vol->flags & HFS_VOL_OPEN))
+ goto done;
+
+ if ((vol->flags & HFS_VOL_USINGCACHE) &&
+ b_finish(vol) == -1)
+ result = -1;
+
+ vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE);
+
+ /* free dynamically allocated structures */
+
+ FREE(vol->vbm);
+
+ vol->vbm = NULL;
+ vol->vbmsz = 0;
+
+ FREE(vol->ext.map);
+ FREE(vol->cat.map);
+
+ vol->ext.map = NULL;
+ vol->cat.map = NULL;
+
+done:
+ return result;
+}
+
+/*
+ * NAME: vol->same()
+ * DESCRIPTION: return 1 iff path is same as open volume
+ */
+int v_same(hfsvol *vol, int os_fd )
+{
+ return vol->os_fd == os_fd;
+}
+
+/*
+ * NAME: vol->geometry()
+ * DESCRIPTION: determine volume location and size (possibly in a partition)
+ */
+int v_geometry(hfsvol *vol, int pnum)
+{
+ Partition map;
+ unsigned long bnum = 0;
+ int found;
+
+ vol->pnum = pnum;
+
+ if (pnum == 0)
+ {
+ vol->vstart = 0;
+ vol->vlen = b_size(vol);
+
+ if (vol->vlen == 0)
+ goto fail;
+ }
+ else
+ {
+ while (pnum--)
+ {
+ found = m_findpmentry(vol, "Apple_HFS", &map, &bnum);
+ if (found == -1 || ! found)
+ goto fail;
+ }
+
+ vol->vstart = map.pmPyPartStart;
+ vol->vlen = map.pmPartBlkCnt;
+
+ if (map.pmDataCnt)
+ {
+ if ((unsigned long) map.pmLgDataStart +
+ (unsigned long) map.pmDataCnt > vol->vlen)
+ ERROR(EINVAL, "partition data overflows partition");
+
+ vol->vstart += (unsigned long) map.pmLgDataStart;
+ vol->vlen = map.pmDataCnt;
+ }
+
+ if (vol->vlen == 0)
+ ERROR(EINVAL, "volume partition is empty");
+ }
+
+ if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS))
+ ERROR(EINVAL, "volume is smaller than 800K");
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: vol->readmdb()
+ * DESCRIPTION: load Master Directory Block into memory
+ */
+int v_readmdb(hfsvol *vol)
+{
+ if (l_getmdb(vol, &vol->mdb, 0) == -1)
+ goto fail;
+
+ if (vol->mdb.drSigWord != HFS_SIGWORD)
+ {
+ if (vol->mdb.drSigWord == HFS_SIGWORD_MFS)
+ ERROR(EINVAL, "MFS volume format not supported");
+ else
+ ERROR(EINVAL, "not a Macintosh HFS volume");
+ }
+
+ if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
+ ERROR(EINVAL, "bad volume allocation block size");
+
+ vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS;
+
+ /* extents pseudo-file structs */
+
+ vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN;
+ vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize;
+ vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize;
+
+ vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
+ vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
+
+ memcpy(&vol->ext.f.cat.u.fil.filExtRec,
+ &vol->mdb.drXTExtRec, sizeof(ExtDataRec));
+
+ f_selectfork(&vol->ext.f, fkData);
+
+ /* catalog pseudo-file structs */
+
+ vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN;
+ vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize;
+ vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize;
+
+ vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
+ vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
+
+ memcpy(&vol->cat.f.cat.u.fil.filExtRec,
+ &vol->mdb.drCTExtRec, sizeof(ExtDataRec));
+
+ f_selectfork(&vol->cat.f, fkData);
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: vol->readvbm()
+ * DESCRIPTION: read volume bitmap into memory
+ */
+int v_readvbm(hfsvol *vol)
+{
+ unsigned int vbmst = vol->mdb.drVBMSt;
+ unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12;
+ block *bp;
+
+ ASSERT(vol->vbm == 0);
+
+ if (vol->mdb.drAlBlSt - vbmst < vbmsz)
+ ERROR(EIO, "volume bitmap collides with volume data");
+
+ vol->vbm = ALLOC(block, vbmsz);
+ if (vol->vbm == NULL)
+ ERROR(ENOMEM, NULL);
+
+ vol->vbmsz = vbmsz;
+
+ for (bp = vol->vbm; vbmsz--; ++bp)
+ {
+ if (b_readlb(vol, vbmst++, bp) == -1)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ FREE(vol->vbm);
+
+ vol->vbm = NULL;
+ vol->vbmsz = 0;
+
+ return -1;
+}
+
+/*
+ * NAME: vol->mount()
+ * DESCRIPTION: load volume information into memory
+ */
+int v_mount(hfsvol *vol)
+{
+ /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */
+
+ if (v_readmdb(vol) == -1 ||
+ v_readvbm(vol) == -1 ||
+ bt_readhdr(&vol->ext) == -1 ||
+ bt_readhdr(&vol->cat) == -1)
+ goto fail;
+
+ if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED)
+ vol->flags |= HFS_VOL_READONLY;
+ else if (vol->flags & HFS_VOL_READONLY)
+ vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
+ else
+ vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
+
+ vol->flags |= HFS_VOL_MOUNTED;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+/*
+ * NAME: vol->catsearch()
+ * DESCRIPTION: search catalog tree
+ */
+int v_catsearch(hfsvol *vol, unsigned long parid, const char *name,
+ CatDataRec *data, char *cname, node *np)
+{
+ CatKeyRec key;
+ byte pkey[HFS_CATKEYLEN];
+ const byte *ptr;
+ node n;
+ int found;
+
+ if (np == NULL)
+ np = &n;
+
+ r_makecatkey(&key, parid, name);
+ r_packcatkey(&key, pkey, NULL);
+
+ found = bt_search(&vol->cat, pkey, np);
+ if (found <= 0)
+ return found;
+
+ ptr = HFS_NODEREC(*np, np->rnum);
+
+ if (cname)
+ {
+ r_unpackcatkey(ptr, &key);
+ strcpy(cname, key.ckrCName);
+ }
+
+ if (data)
+ r_unpackcatdata(HFS_RECDATA(ptr), data);
+
+ return 1;
+}
+
+/*
+ * NAME: vol->extsearch()
+ * DESCRIPTION: search extents tree
+ */
+int v_extsearch(hfsfile *file, unsigned int fabn,
+ ExtDataRec *data, node *np)
+{
+ ExtKeyRec key;
+ ExtDataRec extsave;
+ unsigned int fabnsave;
+ byte pkey[HFS_EXTKEYLEN];
+ const byte *ptr;
+ node n;
+ int found;
+
+ if (np == NULL)
+ np = &n;
+
+ r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn);
+ r_packextkey(&key, pkey, NULL);
+
+ /* in case bt_search() clobbers these */
+
+ memcpy(&extsave, &file->ext, sizeof(ExtDataRec));
+ fabnsave = file->fabn;
+
+ found = bt_search(&file->vol->ext, pkey, np);
+
+ memcpy(&file->ext, &extsave, sizeof(ExtDataRec));
+ file->fabn = fabnsave;
+
+ if (found <= 0)
+ return found;
+
+ if (data)
+ {
+ ptr = HFS_NODEREC(*np, np->rnum);
+ r_unpackextdata(HFS_RECDATA(ptr), data);
+ }
+
+ return 1;
+}
+
+/*
+ * NAME: vol->getthread()
+ * DESCRIPTION: retrieve catalog thread information for a file or directory
+ */
+int v_getthread(hfsvol *vol, unsigned long id,
+ CatDataRec *thread, node *np, int type)
+{
+ CatDataRec rec;
+ int found;
+
+ if (thread == NULL)
+ thread = &rec;
+
+ found = v_catsearch(vol, id, "", thread, NULL, np);
+ if (found == 1 && thread->cdrType != type)
+ ERROR(EIO, "bad thread record");
+
+ return found;
+
+fail:
+ return -1;
+}
+
+
+/*
+ * NAME: vol->resolve()
+ * DESCRIPTION: translate a pathname; return catalog information
+ */
+int v_resolve(hfsvol **vol, const char *path,
+ CatDataRec *data, unsigned long *parid, char *fname, node *np)
+{
+ unsigned long dirid;
+ char name[HFS_MAX_FLEN + 1], *nptr;
+ int found = 0;
+
+ if (*path == 0)
+ ERROR(ENOENT, "empty path");
+
+ if (parid)
+ *parid = 0;
+
+ nptr = strchr(path, ':');
+
+ if (*path == ':' || nptr == NULL)
+ {
+ dirid = (*vol)->cwd; /* relative path */
+
+ if (*path == ':')
+ ++path;
+
+ if (*path == 0)
+ {
+ found = v_getdthread(*vol, dirid, data, NULL);
+ if (found == -1)
+ goto fail;
+
+ if (found)
+ {
+ if (parid)
+ *parid = data->u.dthd.thdParID;
+
+ found = v_catsearch(*vol, data->u.dthd.thdParID,
+ data->u.dthd.thdCName, data, fname, np);
+ if (found == -1)
+ goto fail;
+ }
+
+ goto done;
+ }
+ }
+ else
+ {
+ hfsvol *check;
+
+ dirid = HFS_CNID_ROOTPAR; /* absolute path */
+
+ if (nptr - path > HFS_MAX_VLEN)
+ ERROR(ENAMETOOLONG, NULL);
+
+ strncpy(name, path, nptr - path);
+ name[nptr - path] = 0;
+
+ for (check = hfs_mounts; check; check = check->next)
+ {
+ if (d_relstring(check->mdb.drVN, name) == 0)
+ {
+ *vol = check;
+ break;
+ }
+ }
+ }
+
+ while (1)
+ {
+ while (*path == ':')
+ {
+ ++path;
+
+ found = v_getdthread(*vol, dirid, data, NULL);
+ if (found == -1)
+ goto fail;
+ else if (! found)
+ goto done;
+
+ dirid = data->u.dthd.thdParID;
+ }
+
+ if (*path == 0)
+ {
+ found = v_getdthread(*vol, dirid, data, NULL);
+ if (found == -1)
+ goto fail;
+
+ if (found)
+ {
+ if (parid)
+ *parid = data->u.dthd.thdParID;
+
+ found = v_catsearch(*vol, data->u.dthd.thdParID,
+ data->u.dthd.thdCName, data, fname, np);
+ if (found == -1)
+ goto fail;
+ }
+
+ goto done;
+ }
+
+ nptr = name;
+ while (nptr < name + sizeof(name) - 1 && *path && *path != ':')
+ *nptr++ = *path++;
+
+ if (*path && *path != ':')
+ ERROR(ENAMETOOLONG, NULL);
+
+ *nptr = 0;
+ if (*path == ':')
+ ++path;
+
+ if (parid)
+ *parid = dirid;
+
+ found = v_catsearch(*vol, dirid, name, data, fname, np);
+ if (found == -1)
+ goto fail;
+
+ if (! found)
+ {
+ if (*path && parid)
+ *parid = 0;
+
+ if (*path == 0 && fname)
+ strcpy(fname, name);
+
+ goto done;
+ }
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ if (*path == 0)
+ goto done;
+
+ dirid = data->u.dir.dirDirID;
+ break;
+
+ case cdrFilRec:
+ if (*path == 0)
+ goto done;
+
+ ERROR(ENOTDIR, "invalid pathname");
+
+ default:
+ ERROR(EIO, "unexpected catalog record");
+ }
+ }
+
+done:
+ return found;
+
+fail:
+ return -1;
+}
+
+/* Determine whether the volume is a HFS volume */
+int
+v_probe(int fd, long long offset)
+{
+ MDB *mdb;
+
+ mdb = (MDB*)malloc(2 * 512);
+ os_seek_offset( fd, 2 * 512 + offset );
+ os_read(fd, mdb, 2, 9);
+
+ if (__be16_to_cpu(mdb->drSigWord) != HFS_SIGWORD) {
+ free(mdb);
+ return 0;
+ }
+
+ free(mdb);
+ return -1;
+}