summaryrefslogtreecommitdiff
path: root/libhfs_iso
diff options
context:
space:
mode:
Diffstat (limited to 'libhfs_iso')
-rw-r--r--libhfs_iso/CMakeLists.txt8
-rw-r--r--libhfs_iso/README41
-rw-r--r--libhfs_iso/block.c219
-rw-r--r--libhfs_iso/block.h37
-rw-r--r--libhfs_iso/btree.c740
-rw-r--r--libhfs_iso/btree.h47
-rw-r--r--libhfs_iso/data.c379
-rw-r--r--libhfs_iso/data.h57
-rw-r--r--libhfs_iso/file.c470
-rw-r--r--libhfs_iso/file.h48
-rw-r--r--libhfs_iso/gdata.c20
-rw-r--r--libhfs_iso/hfs.c2098
-rw-r--r--libhfs_iso/hfs.h208
-rw-r--r--libhfs_iso/hybrid.h67
-rw-r--r--libhfs_iso/internal.h369
-rw-r--r--libhfs_iso/low.c529
-rw-r--r--libhfs_iso/low.h111
-rw-r--r--libhfs_iso/node.c473
-rw-r--r--libhfs_iso/node.h48
-rw-r--r--libhfs_iso/record.c551
-rw-r--r--libhfs_iso/record.h52
-rw-r--r--libhfs_iso/volume.c741
-rw-r--r--libhfs_iso/volume.h58
23 files changed, 7371 insertions, 0 deletions
diff --git a/libhfs_iso/CMakeLists.txt b/libhfs_iso/CMakeLists.txt
new file mode 100644
index 0000000..8558690
--- /dev/null
+++ b/libhfs_iso/CMakeLists.txt
@@ -0,0 +1,8 @@
+PROJECT (LIBhfs_iso C)
+INCLUDE_DIRECTORIES(../include ../libhfs_iso ../wodim ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include)
+ADD_DEFINITIONS(-DUSE_LARGEFILES -DABORT_DEEP_ISO_ONLY -DAPPLE_HYB -DUDF -DDVD_VIDEO -DSORTING -DHAVE_CONFIG_H -DUSE_LIBSCHILY -DUSE_SCG)
+
+
+SET(LIBhfs_iso_SRCS block.c btree.c data.c file.c gdata.c hfs.c low.c node.c record.c volume.c)
+
+ADD_LIBRARY (hfs_iso STATIC ${LIBhfs_iso_SRCS})
diff --git a/libhfs_iso/README b/libhfs_iso/README
new file mode 100644
index 0000000..5c6c00b
--- /dev/null
+++ b/libhfs_iso/README
@@ -0,0 +1,41 @@
+# @(#)README 1.1 97/07/21 joerg
+ 06/09/11 christian
+
+Modified version of libhfs (v2.0) to work with mkhybrid.
+
+To complile for mkhybrid, use the #define -DAPPLE_HYB
+
+The libhfs.a created with this option must not be used with other
+hfsutils routines.
+
+James Pearson 18/7/97
+
+Copyright information from hfsutils:
+
+ hfsutils - tools for reading and writing Macintosh HFS volumes
+ Copyright (C) 1996, 1997 Robert Leslie
+
+ This describes the program as shipped with cdrkit, a spinoff from the
+ cdrtools project. However, the cdrtools developers are no longer
+ involved in the development of this spinoff and therefore shall not
+ be made responsible for any problem caused by it. Do not try to get
+ support for this program by contacting the original authors.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+Source: lihfs_iso/README from cdrtools package
+Edited for cdrkit by Christian Fromme <kaner@strace.org>
+
diff --git a/libhfs_iso/block.c b/libhfs_iso/block.c
new file mode 100644
index 0000000..bbca145
--- /dev/null
+++ b/libhfs_iso/block.c
@@ -0,0 +1,219 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)block.c 1.3 01/11/01 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <strdefs.h>
+#include <unixstd.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "block.h"
+#include "low.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif /* DEBUG */
+
+/*
+ * NAME: block->readlb()
+ * DESCRIPTION: read a logical block from a volume
+ */
+int b_readlb(hfsvol *vol, unsigned long num, block *bp)
+{
+#ifndef APPLE_HYB
+ int bytes;
+#endif
+#ifdef APPLE_HYB
+ block *b;
+ hce_mem *hce;
+
+#ifdef DEBUG
+ fprintf(stderr,"b_readlb: start block = %d\n", vol->vstart + num);
+#endif /* DEBUG */
+
+ hce = vol->hce;
+
+/* Check to see if requested block is in the HFS header or catalog/exents
+ files. If it is, read info from memory copy. If not, then something
+ has gone horribly wrong ... */
+
+ if (num < hce->hfs_hdr_size)
+ b = (block *)hce->hfs_hdr + num;
+ else if (num < hce->hfs_hdr_size + hce->hfs_ce_size)
+ b = (block *)hce->hfs_ce + num - hce->hfs_hdr_size;
+ else
+ {
+ ERROR(EIO, "should not happen!");
+ return -1;
+ }
+
+ memcpy(bp, b, HFS_BLOCKSZ);
+
+#else
+
+ if (lseek(vol->fd, (vol->vstart + num) * HFS_BLOCKSZ, SEEK_SET) < 0)
+ {
+ ERROR(errno, "error seeking device");
+ return -1;
+ }
+
+ bytes = read(vol->fd, bp, HFS_BLOCKSZ);
+ if (bytes < 0)
+ {
+ ERROR(errno, "error reading from device");
+ return -1;
+ }
+ else if (bytes == 0)
+ {
+ ERROR(EIO, "read EOF on volume");
+ return -1;
+ }
+ else if (bytes != HFS_BLOCKSZ)
+ {
+ ERROR(EIO, "read incomplete block");
+ return -1;
+ }
+#endif /* APPLE_HYB */
+ return 0;
+}
+
+/*
+ * NAME: block->writelb()
+ * DESCRIPTION: write a logical block to a volume
+ */
+int b_writelb(hfsvol *vol, unsigned long num, block *bp)
+{
+#ifndef APPLE_HYB
+ int bytes;
+#endif
+#ifdef APPLE_HYB
+ block *b;
+ hce_mem *hce;
+
+#ifdef DEBUG
+ fprintf(stderr,"b_writelb: start block = %d\n", vol->vstart + num);
+#endif /* DEBUG */
+
+ hce = vol->hce;
+
+/* Check to see if requested block is in the HFS header or catalog/exents
+ files. If it is, write info to memory copy. If not, then it's a block
+ for an ordinary file - and as we are writing the files later, then just
+ ignore and return OK */
+ if (num < hce->hfs_hdr_size)
+ b = (block *)hce->hfs_hdr + num;
+ else if (num < hce->hfs_hdr_size + hce->hfs_ce_size)
+ b = (block *)hce->hfs_ce + num - hce->hfs_hdr_size;
+ else
+ {
+#ifdef DEBUG
+ fprintf(stderr,"b_writelb: ignoring\n");
+#endif /* DEBUG */
+ return 0;
+ }
+
+ memcpy(b, bp, HFS_BLOCKSZ);
+
+#else
+
+ if (lseek(vol->fd, (vol->vstart + num) * HFS_BLOCKSZ, SEEK_SET) < 0)
+ {
+ ERROR(errno, "error seeking device");
+ return -1;
+ }
+
+ bytes = write(vol->fd, bp, HFS_BLOCKSZ);
+
+ if (bytes < 0)
+ {
+ ERROR(errno, "error writing to device");
+ return -1;
+ }
+ else if (bytes != HFS_BLOCKSZ)
+ {
+ ERROR(EIO, "wrote incomplete block");
+ return -1;
+ }
+#endif /* APPLE_HYB */
+ return 0;
+}
+
+/*
+ * NAME: block->readab()
+ * DESCRIPTION: read a block from an allocation block from a volume
+ */
+int b_readab(hfsvol *vol, unsigned int anum, unsigned int idx, block *bp)
+{
+ /* verify the allocation block exists and is marked as in-use */
+
+ if (anum >= vol->mdb.drNmAlBlks)
+ {
+ ERROR(EIO, "read nonexistent block");
+ return -1;
+ }
+ else if (vol->vbm && ! BMTST(vol->vbm, anum))
+ {
+ ERROR(EIO, "read unallocated block");
+ return -1;
+ }
+
+ return b_readlb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + idx, bp);
+}
+
+/*
+ * NAME: b->writeab()
+ * DESCRIPTION: write a block to an allocation block to a volume
+ */
+int b_writeab(hfsvol *vol, unsigned int anum, unsigned int idx, block *bp)
+{
+ /* verify the allocation block exists and is marked as in-use */
+
+ if (anum >= vol->mdb.drNmAlBlks)
+ {
+ ERROR(EIO, "write nonexistent block");
+ return -1;
+ }
+ else if (vol->vbm && ! BMTST(vol->vbm, anum))
+ {
+ ERROR(EIO, "write unallocated block");
+ return -1;
+ }
+
+ vol->mdb.drAtrb &= ~HFS_ATRB_UMOUNTED;
+ vol->mdb.drLsMod = d_tomtime(time(0));
+ ++vol->mdb.drWrCnt;
+
+ vol->flags |= HFS_UPDATE_MDB;
+
+ return b_writelb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + idx, bp);
+}
diff --git a/libhfs_iso/block.h b/libhfs_iso/block.h
new file mode 100644
index 0000000..ce3932d
--- /dev/null
+++ b/libhfs_iso/block.h
@@ -0,0 +1,37 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)block.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int b_readlb(hfsvol *, unsigned long, block *);
+int b_writelb(hfsvol *, unsigned long, block *);
+
+int b_readab(hfsvol *, unsigned int, unsigned int, block *);
+int b_writeab(hfsvol *, unsigned int, unsigned int, block *);
diff --git a/libhfs_iso/btree.c b/libhfs_iso/btree.c
new file mode 100644
index 0000000..9023428
--- /dev/null
+++ b/libhfs_iso/btree.c
@@ -0,0 +1,740 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)btree.c 1.3 04/06/17 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <strdefs.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "block.h"
+#include "file.h"
+#include "btree.h"
+#include "node.h"
+
+/*
+ * NAME: btree->getnode()
+ * DESCRIPTION: retrieve a numbered node from a B*-tree file
+ */
+int bt_getnode(node *np)
+{
+ btree *bt = np->bt;
+ block *bp = &np->data;
+ unsigned char *ptr;
+ int i;
+
+ /* verify the node exists and is marked as in-use */
+
+ /*
+ * XXX This is the original code. As np->nnum is unsigned, the
+ * XXX comparison for < 0 makes no sense.
+ * XXX Thanks for a hint from Mike.Sullivan@Eng.Sun.COM
+ */
+/* if (np->nnum < 0 || (np->nnum > 0 && np->nnum >= bt->hdr.bthNNodes))*/
+
+ if (np->nnum > 0 && np->nnum >= bt->hdr.bthNNodes)
+ {
+ ERROR(EIO, "read nonexistent b*-tree node");
+ return -1;
+ }
+
+ if (bt->map && ! BMTST(bt->map, np->nnum))
+ {
+ ERROR(EIO, "read unallocated b*-tree node");
+ return -1;
+ }
+
+ if (f_getblock(&bt->f, np->nnum, bp) < 0)
+ return -1;
+
+ ptr = *bp;
+
+ d_fetchl(&ptr, (long *) &np->nd.ndFLink);
+ d_fetchl(&ptr, (long *) &np->nd.ndBLink);
+ d_fetchb(&ptr, (char *) &np->nd.ndType);
+ d_fetchb(&ptr, (char *) &np->nd.ndNHeight);
+ d_fetchw(&ptr, (short *) &np->nd.ndNRecs);
+ d_fetchw(&ptr, &np->nd.ndResv2);
+
+ if (np->nd.ndNRecs > HFS_MAXRECS)
+ {
+ ERROR(EIO, "too many b*-tree node records");
+ return -1;
+ }
+
+ i = np->nd.ndNRecs + 1;
+
+ ptr = *bp + HFS_BLOCKSZ - (2 * i);
+
+ while (i--)
+ d_fetchw(&ptr, (short *) &np->roff[i]);
+
+ return 0;
+}
+
+/*
+ * NAME: btree->putnode()
+ * DESCRIPTION: store a numbered node into a B*-tree file
+ */
+int bt_putnode(node *np)
+{
+ btree *bt = np->bt;
+ block *bp = &np->data;
+ unsigned char *ptr;
+ int i;
+
+ /* verify the node exists and is marked as in-use */
+
+ if (np->nnum && np->nnum >= bt->hdr.bthNNodes)
+ {
+ ERROR(EIO, "write nonexistent b*-tree node");
+ return -1;
+ }
+ else if (bt->map && ! BMTST(bt->map, np->nnum))
+ {
+ ERROR(EIO, "write unallocated b*-tree node");
+ return -1;
+ }
+
+ ptr = *bp;
+
+ d_storel(&ptr, np->nd.ndFLink);
+ d_storel(&ptr, np->nd.ndBLink);
+ d_storeb(&ptr, np->nd.ndType);
+ d_storeb(&ptr, np->nd.ndNHeight);
+ d_storew(&ptr, np->nd.ndNRecs);
+ d_storew(&ptr, np->nd.ndResv2);
+
+ if (np->nd.ndNRecs > HFS_MAXRECS)
+ {
+ ERROR(EIO, "too many b*-tree node records");
+ return -1;
+ }
+
+ i = np->nd.ndNRecs + 1;
+
+ ptr = *bp + HFS_BLOCKSZ - (2 * i);
+
+ while (i--)
+ d_storew(&ptr, np->roff[i]);
+
+ if (f_putblock(&bt->f, np->nnum, bp) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: btree->readhdr()
+ * DESCRIPTION: read the header node of a B*-tree
+ */
+int bt_readhdr(btree *bt)
+{
+ unsigned char *ptr;
+ char *map;
+ int i;
+ unsigned long nnum;
+
+ bt->hdrnd.bt = bt;
+ bt->hdrnd.nnum = 0;
+
+ if (bt_getnode(&bt->hdrnd) < 0)
+ return -1;
+
+ 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");
+ return -1;
+ }
+
+ /* read header record */
+
+ ptr = HFS_NODEREC(bt->hdrnd, 0);
+
+ d_fetchw(&ptr, (short *) &bt->hdr.bthDepth);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthRoot);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthNRecs);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthFNode);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthLNode);
+ d_fetchw(&ptr, (short *) &bt->hdr.bthNodeSize);
+ d_fetchw(&ptr, (short *) &bt->hdr.bthKeyLen);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthNNodes);
+ d_fetchl(&ptr, (long *) &bt->hdr.bthFree);
+
+ for (i = 0; i < 76; ++i)
+ d_fetchb(&ptr, (char *) &bt->hdr.bthResv[i]);
+
+ if (bt->hdr.bthNodeSize != HFS_BLOCKSZ)
+ {
+ ERROR(EINVAL, "unsupported b*-tree node size");
+ return -1;
+ }
+
+ /* read map record; construct btree bitmap */
+ /* don't set bt->map until we're done, since getnode() checks it */
+
+ map = ALLOC(char, HFS_MAP1SZ);
+ if (map == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return -1;
+ }
+
+ 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;
+ char *newmap;
+
+ n.bt = bt;
+ n.nnum = nnum;
+
+ if (bt_getnode(&n) < 0)
+ {
+ FREE(map);
+ return -1;
+ }
+
+ if (n.nd.ndType != ndMapNode ||
+ n.nd.ndNRecs != 1 ||
+ n.roff[0] != 0x00e ||
+ n.roff[1] != 0x1fa)
+ {
+ FREE(map);
+ ERROR(EIO, "malformed b*-tree map node");
+ return -1;
+ }
+
+ newmap = REALLOC(map, char, bt->mapsz + HFS_MAPXSZ);
+ if (newmap == 0)
+ {
+ FREE(map);
+ ERROR(ENOMEM, 0);
+ return -1;
+ }
+ 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;
+}
+
+/*
+ * NAME: btree->writehdr()
+ * DESCRIPTION: write the header node of a B*-tree
+ */
+int bt_writehdr(btree *bt)
+{
+ unsigned char *ptr;
+ char *map;
+ unsigned long mapsz, nnum;
+ int i;
+
+ if (bt->hdrnd.bt != bt ||
+ bt->hdrnd.nnum != 0 ||
+ bt->hdrnd.nd.ndType != ndHdrNode ||
+ bt->hdrnd.nd.ndNRecs != 3)
+ abort();
+
+ ptr = HFS_NODEREC(bt->hdrnd, 0);
+
+ d_storew(&ptr, bt->hdr.bthDepth);
+ d_storel(&ptr, bt->hdr.bthRoot);
+ d_storel(&ptr, bt->hdr.bthNRecs);
+ d_storel(&ptr, bt->hdr.bthFNode);
+ d_storel(&ptr, bt->hdr.bthLNode);
+ d_storew(&ptr, bt->hdr.bthNodeSize);
+ d_storew(&ptr, bt->hdr.bthKeyLen);
+ d_storel(&ptr, bt->hdr.bthNNodes);
+ d_storel(&ptr, bt->hdr.bthFree);
+
+ for (i = 0; i < 76; ++i)
+ d_storeb(&ptr, bt->hdr.bthResv[i]);
+
+ memcpy(HFS_NODEREC(bt->hdrnd, 2), bt->map, HFS_MAP1SZ);
+
+ if (bt_putnode(&bt->hdrnd) < 0)
+ return -1;
+
+ map = bt->map + HFS_MAP1SZ;
+ mapsz = bt->mapsz - HFS_MAP1SZ;
+
+ nnum = bt->hdrnd.nd.ndFLink;
+
+ while (mapsz)
+ {
+ node n;
+
+ if (nnum == 0)
+ {
+ ERROR(EIO, "truncated b*-tree map");
+ return -1;
+ }
+
+ n.bt = bt;
+ n.nnum = nnum;
+
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ if (n.nd.ndType != ndMapNode ||
+ n.nd.ndNRecs != 1 ||
+ n.roff[0] != 0x00e ||
+ n.roff[1] != 0x1fa)
+ {
+ ERROR(EIO, "malformed b*-tree map node");
+ return -1;
+ }
+
+ memcpy(HFS_NODEREC(n, 0), map, HFS_MAPXSZ);
+
+ if (bt_putnode(&n) < 0)
+ return -1;
+
+ map += HFS_MAPXSZ;
+ mapsz -= HFS_MAPXSZ;
+
+ nnum = n.nd.ndFLink;
+ }
+
+ bt->flags &= ~HFS_UPDATE_BTHDR;
+
+ return 0;
+}
+
+/* High-Level B*-Tree Routines ============================================= */
+
+/*
+ * NAME: btree->space()
+ * DESCRIPTION: assert space for new records, or extend the file
+ */
+int bt_space(btree *bt, unsigned int nrecs)
+{
+ unsigned int nnodes;
+ int space;
+
+ nnodes = nrecs * (bt->hdr.bthDepth + 1);
+
+ if (nnodes <= bt->hdr.bthFree)
+ return 0;
+
+ /* make sure the extents tree has room too */
+
+ if (bt != &bt->f.vol->ext)
+ {
+ if (bt_space(&bt->f.vol->ext, 1) < 0)
+ return -1;
+ }
+
+ space = f_alloc(&bt->f);
+ if (space < 0)
+ return -1;
+
+ nnodes = space * (bt->f.vol->mdb.drAlBlkSiz / bt->hdr.bthNodeSize);
+
+ bt->hdr.bthNNodes += nnodes;
+ bt->hdr.bthFree += nnodes;
+
+ bt->flags |= HFS_UPDATE_BTHDR;
+
+ bt->f.vol->flags |= HFS_UPDATE_ALTMDB;
+
+ while (bt->hdr.bthNNodes > bt->mapsz * 8)
+ {
+ char *newmap;
+ node mapnd;
+
+ /* extend tree map */
+
+ newmap = REALLOC(bt->map, char, bt->mapsz + HFS_MAPXSZ);
+ if (newmap == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return -1;
+ }
+
+ memset(newmap + bt->mapsz, 0, HFS_MAPXSZ);
+
+ bt->map = newmap;
+ bt->mapsz += HFS_MAPXSZ;
+
+ n_init(&mapnd, bt, ndMapNode, 0);
+ if (n_new(&mapnd) < 0)
+ return -1;
+
+ /* link the new map node */
+
+ if (bt->hdrnd.nd.ndFLink == 0)
+ {
+ bt->hdrnd.nd.ndFLink = mapnd.nnum;
+ mapnd.nd.ndBLink = 0;
+ }
+ else
+ {
+ node n;
+
+ n.bt = bt;
+ n.nnum = bt->hdrnd.nd.ndFLink;
+
+ for (;;)
+ {
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ if (n.nd.ndFLink == 0)
+ break;
+
+ n.nnum = n.nd.ndFLink;
+ }
+
+ n.nd.ndFLink = mapnd.nnum;
+ mapnd.nd.ndBLink = n.nnum;
+
+ if (bt_putnode(&n) < 0)
+ return -1;
+ }
+
+ mapnd.nd.ndNRecs = 1;
+ mapnd.roff[1] = 0x1fa;
+
+ if (bt_putnode(&mapnd) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: btree->insertx()
+ * DESCRIPTION: recursively locate a node and insert a record
+ */
+int bt_insertx(node *np, unsigned char *record, int *reclen)
+{
+ node child;
+ unsigned char *rec;
+
+ if (n_search(np, record))
+ {
+ ERROR(EIO, "b*-tree record already exists");
+ return -1;
+ }
+
+ switch ((unsigned char) np->nd.ndType)
+ {
+ case ndIndxNode:
+ if (np->rnum < 0)
+ rec = HFS_NODEREC(*np, 0);
+ else
+ rec = HFS_NODEREC(*np, np->rnum);
+
+ child.bt = np->bt;
+ child.nnum = d_getl(HFS_RECDATA(rec));
+
+ if (bt_getnode(&child) < 0 ||
+ bt_insertx(&child, record, reclen) < 0)
+ return -1;
+
+ if (np->rnum < 0)
+ {
+ n_index(np->bt, HFS_NODEREC(child, 0), child.nnum, rec, 0);
+ if (*reclen == 0)
+ return bt_putnode(np);
+ }
+
+ return *reclen ? n_insert(np, record, reclen) : 0;
+
+ case ndLeafNode:
+ return n_insert(np, record, reclen);
+
+ default:
+ ERROR(EIO, "unexpected b*-tree node");
+ return -1;
+ }
+}
+
+/*
+ * NAME: btree->insert()
+ * DESCRIPTION: insert a new node record into a tree
+ */
+int bt_insert(btree *bt, unsigned char *record, int reclen)
+{
+ node root;
+
+ if (bt->hdr.bthRoot == 0)
+ {
+ /* create root node */
+
+ n_init(&root, bt, ndLeafNode, 1);
+ if (n_new(&root) < 0 ||
+ bt_putnode(&root) < 0)
+ return -1;
+
+ bt->hdr.bthDepth = 1;
+ bt->hdr.bthRoot = root.nnum;
+ bt->hdr.bthFNode = root.nnum;
+ bt->hdr.bthLNode = root.nnum;
+
+ bt->flags |= HFS_UPDATE_BTHDR;
+ }
+ else
+ {
+ root.bt = bt;
+ root.nnum = bt->hdr.bthRoot;
+
+ if (bt_getnode(&root) < 0)
+ return -1;
+ }
+
+ if (bt_insertx(&root, record, &reclen) < 0)
+ return -1;
+
+ if (reclen)
+ {
+ unsigned char oroot[HFS_MAXRECLEN];
+ int orootlen;
+
+ /* root node was split; create a new root */
+
+ n_index(bt, HFS_NODEREC(root, 0), root.nnum, oroot, &orootlen);
+
+ n_init(&root, bt, ndIndxNode, root.nd.ndNHeight + 1);
+ if (n_new(&root) < 0)
+ return -1;
+
+ ++bt->hdr.bthDepth;
+ bt->hdr.bthRoot = root.nnum;
+
+ bt->flags |= HFS_UPDATE_BTHDR;
+
+ /* insert index records for new root */
+
+ n_search(&root, oroot);
+ n_insertx(&root, oroot, orootlen);
+
+ n_search(&root, record);
+ n_insertx(&root, record, reclen);
+
+ if (bt_putnode(&root) < 0)
+ return -1;
+ }
+
+ ++bt->hdr.bthNRecs;
+ bt->flags |= HFS_UPDATE_BTHDR;
+
+ return 0;
+}
+
+/*
+ * NAME: btree->deletex()
+ * DESCRIPTION: recursively locate a node and delete a record
+ */
+int bt_deletex(node *np, unsigned char *key, unsigned char *record, int *flag)
+{
+ node child;
+ unsigned char *rec;
+ int found;
+
+ found = n_search(np, key);
+
+ switch ((unsigned char) np->nd.ndType)
+ {
+ case ndIndxNode:
+ if (np->rnum < 0)
+ {
+ ERROR(EIO, "b*-tree record not found");
+ return -1;
+ }
+
+ rec = HFS_NODEREC(*np, np->rnum);
+
+ child.bt = np->bt;
+ child.nnum = d_getl(HFS_RECDATA(rec));
+
+ if (bt_getnode(&child) < 0 ||
+ bt_deletex(&child, key, rec, flag) < 0)
+ return -1;
+
+ if (*flag)
+ {
+ *flag = 0;
+
+ if (HFS_RECKEYLEN(rec) == 0)
+ return n_delete(np, record, flag);
+
+ if (np->rnum == 0)
+ {
+ n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);
+ *flag = 1;
+ }
+
+ return bt_putnode(np);
+ }
+
+ return 0;
+
+ case ndLeafNode:
+ if (found == 0)
+ {
+ ERROR(EIO, "b*-tree record not found");
+ return -1;
+ }
+
+ return n_delete(np, record, flag);
+
+ default:
+ ERROR(EIO, "unexpected b*-tree node");
+ return -1;
+ }
+}
+
+/*
+ * NAME: btree->delete()
+ * DESCRIPTION: remove a node record from a tree
+ */
+int bt_delete(btree *bt, unsigned char *key)
+{
+ node root;
+ unsigned char record[HFS_MAXRECLEN];
+ int flag = 0;
+
+ root.bt = bt;
+ root.nnum = bt->hdr.bthRoot;
+
+ if (root.nnum == 0)
+ {
+ ERROR(EIO, "empty b*-tree");
+ return -1;
+ }
+
+ if (bt_getnode(&root) < 0 ||
+ bt_deletex(&root, key, record, &flag) < 0)
+ return -1;
+
+ if (bt->hdr.bthDepth > 1 && root.nd.ndNRecs == 1)
+ {
+ unsigned char *rec;
+
+ /* chop the root */
+
+ rec = HFS_NODEREC(root, 0);
+
+ --bt->hdr.bthDepth;
+ bt->hdr.bthRoot = d_getl(HFS_RECDATA(rec));
+
+ n_free(&root);
+ }
+ else if (bt->hdr.bthDepth == 1 && root.nd.ndNRecs == 0)
+ {
+ /* delete the root node */
+
+ bt->hdr.bthDepth = 0;
+ bt->hdr.bthRoot = 0;
+ bt->hdr.bthFNode = 0;
+ bt->hdr.bthLNode = 0;
+
+ n_free(&root);
+ }
+
+ --bt->hdr.bthNRecs;
+ bt->flags |= HFS_UPDATE_BTHDR;
+
+ return 0;
+}
+
+/*
+ * NAME: btree->search()
+ * DESCRIPTION: locate a data record given a search key
+ */
+int bt_search(btree *bt, unsigned char *key, node *np)
+{
+ np->bt = bt;
+ np->nnum = bt->hdr.bthRoot;
+
+ if (np->nnum == 0)
+ {
+ ERROR(ENOENT, 0);
+ return 0;
+ }
+
+ for (;;)
+ {
+ int found;
+ unsigned char *rec;
+
+ if (bt_getnode(np) < 0)
+ return -1;
+
+ found = n_search(np, key);
+
+ switch ((unsigned char) np->nd.ndType)
+ {
+ case ndIndxNode:
+ if (np->rnum < 0)
+ {
+ ERROR(ENOENT, 0);
+ return 0;
+ }
+
+ rec = HFS_NODEREC(*np, np->rnum);
+ np->nnum = d_getl(HFS_RECDATA(rec));
+ break;
+
+ case ndLeafNode:
+ if (! found)
+ ERROR(ENOENT, 0);
+
+ return found;
+
+ default:
+ ERROR(EIO, "unexpected b*-tree node");
+ return -1;
+ }
+ }
+}
diff --git a/libhfs_iso/btree.h b/libhfs_iso/btree.h
new file mode 100644
index 0000000..c4b7629
--- /dev/null
+++ b/libhfs_iso/btree.h
@@ -0,0 +1,47 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)btree.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int bt_getnode(node *);
+int bt_putnode(node *);
+
+int bt_readhdr(btree *);
+int bt_writehdr(btree *);
+
+int bt_space(btree *, unsigned int);
+
+int bt_insertx(node *, unsigned char *, int *);
+int bt_insert(btree *, unsigned char *, int);
+
+int bt_deletex(node *, unsigned char *, unsigned char *, int *);
+int bt_delete(btree *, unsigned char *);
+
+int bt_search(btree *, unsigned char *, node *);
diff --git a/libhfs_iso/data.c b/libhfs_iso/data.c
new file mode 100644
index 0000000..3f503f4
--- /dev/null
+++ b/libhfs_iso/data.c
@@ -0,0 +1,379 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)data.c 1.5 02/02/10 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <strdefs.h>
+#include <timedefs.h>
+
+#include "internal.h"
+#include "data.h"
+#include "btree.h"
+
+#ifdef APPLE_HYB
+/*
+ * Depending on the version, AppleDouble/Single stores dates
+ * relative to 1st Jan 1904 (v1) or 1st Jan 2000 (v2)
+ *
+ * DUTDIFF is the difference between 1st Jan 2000 and
+ * 1st Jan 1970 (Unix epoch)).
+ */
+
+#define DUTDIFF 946684800L
+#endif /* APPLE_HYB */
+#define MUTDIFF 2082844800L
+#define TZNONE 0x0FFFFFFFL /* A timezone diff that cannot occur */
+
+static void calctzdiff(void);
+
+static
+unsigned long tzdiff = TZNONE;
+
+static
+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->getb()
+ * DESCRIPTION: marshal 1 byte into local host format
+ */
+char d_getb(unsigned char *ptr)
+{
+ return (char) ptr[0];
+}
+
+/*
+ * NAME: data->getw()
+ * DESCRIPTION: marshal 2 bytes into local host format
+ */
+short d_getw(unsigned char *ptr)
+{
+ return (short)
+ ((ptr[0] << 8) |
+ (ptr[1] << 0));
+}
+
+/*
+ * NAME: data->getl()
+ * DESCRIPTION: marshal 4 bytes into local host format
+ */
+long d_getl(unsigned char *ptr)
+{
+ return (long)
+ ((ptr[0] << 24) |
+ (ptr[1] << 16) |
+ (ptr[2] << 8) |
+ (ptr[3] << 0));
+}
+
+/*
+ * NAME: data->putb()
+ * DESCRIPTION: marshal 1 byte out to Macintosh (big-endian) format
+ */
+#ifdef PROTOTYPES
+void d_putb(unsigned char *ptr, char data)
+#else
+void d_putb(unsigned char *ptr, char data)
+#endif
+{
+ ptr[0] = (unsigned char) data;
+}
+
+/*
+ * NAME: data->putw()
+ * DESCRIPTION: marshal 2 bytes out to Macintosh (big-endian) format
+ */
+#ifdef PROTOTYPES
+void d_putw(unsigned char *ptr, short data)
+#else
+void d_putw(unsigned char *ptr, short data)
+#endif
+{
+ ptr[0] = ((unsigned) data & 0xff00) >> 8;
+ ptr[1] = ((unsigned) data & 0x00ff) >> 0;
+}
+
+/*
+ * NAME: data->putl()
+ * DESCRIPTION: marshal 4 bytes out to Macintosh (big-endian) format
+ */
+void d_putl(unsigned char *ptr, long data)
+{
+ ptr[0] = ((unsigned long) data & 0xff000000) >> 24;
+ ptr[1] = ((unsigned long) data & 0x00ff0000) >> 16;
+ ptr[2] = ((unsigned long) data & 0x0000ff00) >> 8;
+ ptr[3] = ((unsigned long) data & 0x000000ff) >> 0;
+}
+
+/*
+ * NAME: data->fetchb()
+ * DESCRIPTION: incrementally retrieve a byte of data
+ */
+void d_fetchb(unsigned char **ptr, char *dest)
+{
+ *dest = d_getb(*ptr);
+ *ptr += 1;
+}
+
+/*
+ * NAME: data->fetchw()
+ * DESCRIPTION: incrementally retrieve a word of data
+ */
+void d_fetchw(unsigned char **ptr, short *dest)
+{
+ *dest = d_getw(*ptr);
+ *ptr += 2;
+}
+
+/*
+ * NAME: data->fetchl()
+ * DESCRIPTION: incrementally retrieve a long word of data
+ */
+void d_fetchl(unsigned char **ptr, long *dest)
+{
+ *dest = d_getl(*ptr);
+ *ptr += 4;
+}
+
+/*
+ * NAME: data->fetchs()
+ * DESCRIPTION: incrementally retrieve a string
+ */
+void d_fetchs(unsigned char **ptr, char *dest, int size)
+{
+ int len;
+ char blen;
+
+ d_fetchb(ptr, &blen);
+ len = blen;
+
+ if (len > 0 && len < size)
+ memcpy(dest, *ptr, len);
+ else
+ len = 0;
+
+ dest[len] = 0;
+
+ *ptr += size - 1;
+}
+
+/*
+ * NAME: data->storeb()
+ * DESCRIPTION: incrementally store a byte of data
+ */
+#ifdef PROTOTYPES
+void d_storeb(unsigned char **ptr, char data)
+#else
+void d_storeb(unsigned char **ptr, char data)
+#endif
+{
+ d_putb(*ptr, data);
+ *ptr += 1;
+}
+
+/*
+ * NAME: data->storew()
+ * DESCRIPTION: incrementally store a word of data
+ */
+#ifdef PROTOTYPES
+void d_storew(unsigned char **ptr, short data)
+#else
+void d_storew(unsigned char **ptr, short data)
+#endif
+{
+ d_putw(*ptr, data);
+ *ptr += 2;
+}
+
+/*
+ * NAME: data->storel()
+ * DESCRIPTION: incrementally store a long word of data
+ */
+void d_storel(unsigned char **ptr, long data)
+{
+ d_putl(*ptr, data);
+ *ptr += 4;
+}
+
+/*
+ * NAME: data->stores()
+ * DESCRIPTION: incrementally store a string
+ */
+void d_stores(unsigned char **ptr, char *src, int size)
+{
+ int len;
+
+ len = strlen(src);
+ if (len > --size)
+ len = 0;
+
+ d_storeb(ptr, (unsigned char) len);
+
+ memcpy(*ptr, src, len);
+ memset(*ptr + len, 0, size - len);
+
+ *ptr += size;
+}
+
+/*
+ * NAME: calctzdiff()
+ * DESCRIPTION: calculate the timezone difference between local time and UTC
+ */
+static void calctzdiff()
+{
+ time_t t;
+ int isdst;
+ struct tm 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;
+}
+
+/*
+ * NAME: data->tomtime()
+ * DESCRIPTION: convert UNIX time to Macintosh time
+ */
+unsigned long d_tomtime(unsigned long secs)
+{
+ time_t utime = secs;
+
+ if (tzdiff == TZNONE)
+ calctzdiff();
+
+ return utime + tzdiff + MUTDIFF;
+}
+
+/*
+ * NAME: data->toutime()
+ * DESCRIPTION: convert Macintosh time to UNIX time
+ */
+unsigned long d_toutime(unsigned long secs)
+{
+ time_t utime = secs;
+
+ if (tzdiff == TZNONE)
+ calctzdiff();
+
+ return utime - MUTDIFF - tzdiff;
+}
+
+#ifdef APPLE_HYB
+/*
+ * NAME: data->dtoutime()
+ * DESCRIPTION: convert Apple Double v2 time to UNIX time
+ */
+unsigned long d_dtoutime(long secs)
+{
+ time_t utime = secs;
+
+ if (tzdiff == TZNONE)
+ calctzdiff();
+
+ return utime + DUTDIFF - tzdiff;
+}
+#endif /* APPLE_HYB */
+
+/*
+ * NAME: data->relstring()
+ * DESCRIPTION: compare two strings as per MacOS for HFS
+ */
+int d_relstring(char *str1, char *str2)
+{
+ 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;
+}
diff --git a/libhfs_iso/data.h b/libhfs_iso/data.h
new file mode 100644
index 0000000..b3a68a5
--- /dev/null
+++ b/libhfs_iso/data.h
@@ -0,0 +1,57 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)data.h 1.2 01/11/11 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+char d_getb(unsigned char *);
+short d_getw(unsigned char *);
+long d_getl(unsigned char *);
+
+void d_putb(unsigned char *, char);
+void d_putw(unsigned char *, short);
+void d_putl(unsigned char *, long);
+
+void d_fetchb(unsigned char **, char *);
+void d_fetchw(unsigned char **, short *);
+void d_fetchl(unsigned char **, long *);
+void d_fetchs(unsigned char **, char *, int);
+
+void d_storeb(unsigned char **, char);
+void d_storew(unsigned char **, short);
+void d_storel(unsigned char **, long);
+void d_stores(unsigned char **, char *, int);
+
+unsigned long d_tomtime(unsigned long);
+unsigned long d_toutime(unsigned long);
+#ifdef APPLE_HYB
+unsigned long d_dtoutime(long);
+#endif /* APPLE_HYB */
+
+int d_relstring(char *, char *);
diff --git a/libhfs_iso/file.c b/libhfs_iso/file.c
new file mode 100644
index 0000000..a0198c8
--- /dev/null
+++ b/libhfs_iso/file.c
@@ -0,0 +1,470 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)file.c 1.3 04/06/17 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <strdefs.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "block.h"
+#include "file.h"
+#include "btree.h"
+#include "record.h"
+#include "volume.h"
+
+/* #include <stdio.h> */
+
+
+/*
+ * NAME: file->selectfork()
+ * DESCRIPTION: choose a fork for file operations
+ */
+void f_selectfork(hfsfile *file, int ffork)
+{
+ if (ffork == 0)
+ {
+ file->fork = fkData;
+ memcpy(file->ext, file->cat.u.fil.filExtRec, sizeof(ExtDataRec));
+ }
+ else
+ {
+ file->fork = fkRsrc;
+ memcpy(file->ext, 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, unsigned long **lglen, unsigned long **pylen,
+ ExtDataRec **extrec)
+{
+ if (file->fork == fkData)
+ {
+ if (lglen)
+ *lglen = &file->cat.u.fil.filLgLen;
+ if (pylen)
+ *pylen = &file->cat.u.fil.filPyLen;
+ if (extrec)
+ *extrec = &file->cat.u.fil.filExtRec;
+ }
+ else
+ {
+ if (lglen)
+ *lglen = &file->cat.u.fil.filRLgLen;
+ if (pylen)
+ *pylen = &file->cat.u.fil.filRPyLen;
+ if (extrec)
+ *extrec = &file->cat.u.fil.filRExtRec;
+ }
+}
+
+/*
+ * NAME: file->doblock()
+ * DESCRIPTION: read or write a numbered block from a file
+ */
+int f_doblock(hfsfile *file, unsigned long number, block *bp,
+ int (*func)(hfsvol *, unsigned int, unsigned int, block *))
+{
+ unsigned int abnum;
+ unsigned int blnum;
+ unsigned int fabn;
+ int i;
+
+ abnum = number / file->vol->lpa;
+ blnum = number % file->vol->lpa;
+
+ /* locate the appropriate extent record */
+
+ fabn = file->fabn;
+
+ if (abnum < fabn)
+ {
+ ExtDataRec *extrec;
+
+ f_getptrs(file, 0, 0, &extrec);
+
+ fabn = file->fabn = 0;
+ memcpy(file->ext, extrec, sizeof(ExtDataRec));
+ }
+ else
+ abnum -= fabn;
+
+ for (;;)
+ {
+ unsigned int num;
+
+ for (i = 0; i < 3; ++i)
+ {
+ num = file->ext[i].xdrNumABlks;
+
+#ifdef APPLE_HYB
+ if (i > 0) {
+/* SHOULD NOT HAPPEN! - all the files should not be fragmented
+ if this happens, then a serious problem has occured, may be
+ a hard linked file? */
+#ifdef DEBUG
+ fprintf(stderr,"fragmented file: %s %d\n",file->name, i); */
+#endif /* DEBUG */
+ ERROR(HCE_ERROR, "Possible Catalog file overflow - please report error");
+ return -1;
+ }
+#endif /* APPLE_HYB */
+ if (abnum < num)
+ return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp);
+
+ fabn += num;
+ abnum -= num;
+ }
+
+ if (v_extsearch(file, fabn, &file->ext, 0) <= 0)
+ return -1;
+
+ file->fabn = fabn;
+ }
+}
+
+/*
+ * NAME: file->alloc()
+ * DESCRIPTION: reserve disk blocks for a file
+ */
+int f_alloc(hfsfile *file)
+{
+ hfsvol *vol = file->vol;
+ ExtDescriptor blocks;
+ ExtDataRec *extrec;
+ unsigned long *pylen, clumpsz;
+ unsigned int start, end;
+ node n;
+ int i;
+
+ clumpsz = file->clump;
+ if (clumpsz == 0)
+ clumpsz = vol->mdb.drClpSiz;
+
+ blocks.xdrNumABlks = clumpsz / vol->mdb.drAlBlkSiz;
+
+ if (v_allocblocks(vol, &blocks) < 0)
+ return -1;
+
+ /* update the file's extents */
+
+ f_getptrs(file, 0, &pylen, &extrec);
+
+ start = file->fabn;
+ end = *pylen / vol->mdb.drAlBlkSiz;
+
+ n.nnum = 0;
+ i = -1;
+
+ while (start < end)
+ {
+ for (i = 0; i < 3; ++i)
+ {
+ unsigned int num;
+
+ num = file->ext[i].xdrNumABlks;
+ start += num;
+
+ if (start == end)
+ break;
+ else if (start > end)
+ {
+ v_freeblocks(vol, &blocks);
+ ERROR(EIO, "file extents exceed file physical length");
+ return -1;
+ }
+ else if (num == 0)
+ {
+ v_freeblocks(vol, &blocks);
+ ERROR(EIO, "empty file extent");
+ return -1;
+ }
+ }
+
+ if (start == end)
+ break;
+
+ if (v_extsearch(file, start, &file->ext, &n) <= 0)
+ {
+ v_freeblocks(vol, &blocks);
+ return -1;
+ }
+
+ file->fabn = start;
+ }
+
+ if (i >= 0 &&
+ file->ext[i].xdrStABN + file->ext[i].xdrNumABlks == blocks.xdrStABN)
+ file->ext[i].xdrNumABlks += blocks.xdrNumABlks;
+ else
+ {
+ /* create a new extent descriptor */
+
+ if (++i < 3)
+ file->ext[i] = blocks;
+ else
+ {
+ ExtKeyRec key;
+ unsigned char record[HFS_EXTRECMAXLEN];
+ int reclen;
+
+ /* record is full; create a new one */
+
+ file->ext[0] = blocks;
+
+ for (i = 1; i < 3; ++i)
+ {
+ file->ext[i].xdrStABN = 0;
+ file->ext[i].xdrNumABlks = 0;
+ }
+
+ file->fabn = start;
+
+ r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, end);
+ r_packextkey(&key, record, &reclen);
+ r_packextdata(&file->ext, HFS_RECDATA(record), &reclen);
+
+ if (bt_insert(&vol->ext, record, reclen) < 0)
+ {
+ v_freeblocks(vol, &blocks);
+ return -1;
+ }
+
+ i = -1;
+ }
+ }
+
+ if (i >= 0)
+ {
+ /* store the modified extent record */
+
+ if (file->fabn)
+ {
+ if ((n.nnum == 0 &&
+ v_extsearch(file, file->fabn, 0, &n) <= 0) ||
+ v_putextrec(&file->ext, &n) < 0)
+ {
+ v_freeblocks(vol, &blocks);
+ return -1;
+ }
+ }
+ else
+ memcpy(extrec, file->ext, sizeof(ExtDataRec));
+ }
+
+ *pylen += blocks.xdrNumABlks * vol->mdb.drAlBlkSiz;
+
+ file->flags |= HFS_UPDATE_CATREC;
+
+ return blocks.xdrNumABlks;
+}
+
+/*
+ * NAME: file->trunc()
+ * DESCRIPTION: release disk blocks unneeded by a file
+ */
+int f_trunc(hfsfile *file)
+{
+ ExtDataRec *extrec;
+ unsigned long *lglen, *pylen, alblksz, newpylen;
+ unsigned int dlen, start, end;
+ node n;
+ int i;
+
+ f_getptrs(file, &lglen, &pylen, &extrec);
+
+ alblksz = file->vol->mdb.drAlBlkSiz;
+ newpylen = (*lglen / alblksz + (*lglen % alblksz != 0)) * alblksz;
+
+ if (newpylen > *pylen)
+ {
+ ERROR(EIO, "file size exceeds physical length");
+ return -1;
+ }
+ else if (newpylen == *pylen)
+ return 0;
+
+ dlen = (*pylen - newpylen) / alblksz;
+
+ start = file->fabn;
+ end = newpylen / alblksz;
+
+ if (start >= end)
+ {
+ start = file->fabn = 0;
+ memcpy(file->ext, extrec, sizeof(ExtDataRec));
+ }
+
+ n.nnum = 0;
+ i = -1;
+
+ while (start < end)
+ {
+ for (i = 0; i < 3; ++i)
+ {
+ unsigned int num;
+
+ num = file->ext[i].xdrNumABlks;
+ start += num;
+
+ if (start >= end)
+ break;
+ else if (num == 0)
+ {
+ ERROR(EIO, "empty file extent");
+ return -1;
+ }
+ }
+
+ if (start >= end)
+ break;
+
+ if (v_extsearch(file, start, &file->ext, &n) <= 0)
+ return -1;
+
+ file->fabn = start;
+ }
+
+ if (start > end)
+ {
+ ExtDescriptor blocks;
+
+ file->ext[i].xdrNumABlks -= start - end;
+ dlen -= start - end;
+
+ blocks.xdrStABN = file->ext[i].xdrStABN + file->ext[i].xdrNumABlks;
+ blocks.xdrNumABlks = start - end;
+
+ v_freeblocks(file->vol, &blocks);
+ }
+
+ *pylen = newpylen;
+
+ file->flags |= HFS_UPDATE_CATREC;
+
+ do
+ {
+ while (dlen && ++i < 3)
+ {
+ unsigned int num;
+
+ num = file->ext[i].xdrNumABlks;
+ start += num;
+
+ if (num == 0)
+ {
+ ERROR(EIO, "empty file extent");
+ return -1;
+ }
+ else if (num > dlen)
+ {
+ ERROR(EIO, "file extents exceed physical size");
+ return -1;
+ }
+
+ dlen -= num;
+ v_freeblocks(file->vol, &file->ext[i]);
+
+ file->ext[i].xdrStABN = 0;
+ file->ext[i].xdrNumABlks = 0;
+ }
+
+ if (file->fabn)
+ {
+ if (n.nnum == 0 &&
+ v_extsearch(file, file->fabn, 0, &n) <= 0)
+ return -1;
+
+ if (file->ext[0].xdrNumABlks)
+ {
+ if (v_putextrec(&file->ext, &n) < 0)
+ return -1;
+ }
+ else
+ {
+ if (bt_delete(&file->vol->ext, HFS_NODEREC(n, n.rnum)) < 0)
+ return -1;
+
+ n.nnum = 0;
+ }
+ }
+ else
+ memcpy(extrec, file->ext, sizeof(ExtDataRec));
+
+ if (dlen)
+ {
+ if (v_extsearch(file, start, &file->ext, &n) <= 0)
+ return -1;
+
+ file->fabn = start;
+ i = -1;
+ }
+ }
+ while (dlen);
+
+ return 0;
+}
+
+/*
+ * NAME: file->flush()
+ * DESCRIPTION: flush all pending changes to an open file
+ */
+int f_flush(hfsfile *file)
+{
+ hfsvol *vol = file->vol;
+
+ if (! (vol->flags & HFS_READONLY))
+ {
+ if (file->flags & HFS_UPDATE_CATREC)
+ {
+ node n;
+
+ file->cat.u.fil.filStBlk = file->cat.u.fil.filExtRec[0].xdrStABN;
+ file->cat.u.fil.filRStBlk = file->cat.u.fil.filRExtRec[0].xdrStABN;
+ file->cat.u.fil.filClpSize = file->clump;
+
+ if (v_catsearch(file->vol, file->parid, file->name, 0, 0, &n) <= 0 ||
+ v_putcatrec(&file->cat, &n) < 0)
+ return -1;
+
+ file->flags &= ~HFS_UPDATE_CATREC;
+ }
+ }
+
+ return 0;
+}
diff --git a/libhfs_iso/file.h b/libhfs_iso/file.h
new file mode 100644
index 0000000..9b95bd6
--- /dev/null
+++ b/libhfs_iso/file.h
@@ -0,0 +1,48 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)file.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+enum {
+ fkData = 0x00,
+ fkRsrc = 0xff
+};
+
+void f_selectfork(hfsfile *, int);
+void f_getptrs(hfsfile *, unsigned long **, unsigned long **, ExtDataRec **);
+
+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, b_writeab)
+
+int f_alloc(hfsfile *);
+int f_flush(hfsfile *);
diff --git a/libhfs_iso/gdata.c b/libhfs_iso/gdata.c
new file mode 100644
index 0000000..7642083
--- /dev/null
+++ b/libhfs_iso/gdata.c
@@ -0,0 +1,20 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)gdata.c 1.1 01/01/21 Copyright 2001 J. Schilling */
+
+#include <mconfig.h>
+#include "internal.h"
+
+char *hfs_error = "no error"; /* static error string */
+hfsvol *hfs_mounts; /* linked list of mounted volumes */
+hfsvol *hfs_curvol; /* current volume */
diff --git a/libhfs_iso/hfs.c b/libhfs_iso/hfs.c
new file mode 100644
index 0000000..fb63ef4
--- /dev/null
+++ b/libhfs_iso/hfs.c
@@ -0,0 +1,2098 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)hfs.c 1.9 04/06/17 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* APPLE_HYB James Pearson j.pearson@ps.ucl.ac.uk 16/7/97 */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <fctldefs.h>
+#include <errno.h>
+#include <strdefs.h>
+#include <ctype.h>
+#include <statdefs.h>
+
+#include "internal.h"
+#include "data.h"
+#include "block.h"
+#include "low.h"
+#include "file.h"
+#include "btree.h"
+#include "node.h"
+#include "record.h"
+#include "volume.h"
+#include "hfs.h"
+
+/* High-Level Volume Routines ============================================== */
+
+/*
+ * NAME: hfs->mount()
+ * DESCRIPTION: open an HFS volume; return volume descriptor or 0 (error)
+ */
+#ifdef APPLE_HYB
+hfsvol *hfs_mount(hce_mem *hce, int pnum, int flags)
+#else
+hfsvol *hfs_mount(char *path, int pnum, int flags)
+#endif /* APPLE_HYB */
+{
+#ifndef APPLE_HYB
+ struct stat dev;
+#endif
+ hfsvol *vol = 0;
+
+#ifndef APPLE_HYB
+ /* see if the volume is already mounted */
+
+ if (stat(path, &dev) >= 0)
+ {
+ struct stat mdev;
+ hfsvol *check;
+
+ for (check = hfs_mounts; check; check = check->next)
+ {
+ if (fstat(check->fd, &mdev) >= 0 &&
+ mdev.st_dev == dev.st_dev &&
+ mdev.st_ino == dev.st_ino &&
+ (check->pnum == 0 || check->pnum == pnum))
+ {
+ /* verify compatible read/write mode */
+
+ if (((check->flags & HFS_READONLY) &&
+ ! (flags & O_WRONLY)) ||
+ (! (check->flags & HFS_READONLY) &&
+ (flags & (O_WRONLY | O_RDWR))))
+ {
+ vol = check;
+ break;
+ }
+ }
+ }
+ }
+#endif /* APPLE_HYB */
+ if (vol == 0)
+ {
+ vol = ALLOC(hfsvol, 1);
+ if (vol == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return 0;
+ }
+
+ vol->flags = 0;
+ vol->pnum = pnum;
+ vol->vstart = 0;
+ vol->vlen = 0;
+ vol->lpa = 0;
+ vol->vbm = 0;
+ vol->cwd = HFS_CNID_ROOTDIR;
+
+ vol->refs = 0;
+ vol->files = 0;
+ vol->dirs = 0;
+ vol->prev = 0;
+ vol->next = 0;
+
+ vol->ext.map = 0;
+ vol->ext.mapsz = 0;
+ vol->ext.flags = 0;
+ vol->ext.compare = r_compareextkeys;
+
+ vol->cat.map = 0;
+ vol->cat.mapsz = 0;
+ vol->cat.flags = 0;
+ vol->cat.compare = r_comparecatkeys;
+
+ /* open and lock the device */
+
+#ifdef APPLE_HYB
+ vol->fd = 3; /* any +ve number will do? */
+ vol->hce = hce; /* store the extra with the vol info */
+#else
+ if (flags & (O_WRONLY | O_RDWR))
+ {
+ vol->fd = open(path, O_RDWR);
+ if (vol->fd >= 0 && l_lockvol(vol) < 0)
+ {
+ close(vol->fd);
+ vol->fd = -2;
+ }
+ }
+
+ if (! (flags & (O_WRONLY | O_RDWR)) ||
+ (vol->fd < 0 &&
+ (errno == EROFS || errno == EACCES || errno == EAGAIN) &&
+ (flags & O_RDWR)))
+ {
+ vol->flags |= HFS_READONLY;
+ vol->fd = open(path, O_RDONLY);
+ if (vol->fd >= 0 && l_lockvol(vol) < 0)
+ {
+ close(vol->fd);
+ vol->fd = -2;
+ }
+ }
+
+ if (vol->fd < 0)
+ {
+ if (vol->fd != -2)
+ ERROR(errno, "error opening device");
+
+ v_destruct(vol);
+
+ return 0;
+ }
+#endif /* APPLE_HYB */
+
+ /* find out what kind of media this is and read the MDB */
+
+ if (l_readblock0(vol) < 0 ||
+ l_readmdb(vol) < 0)
+ {
+#ifndef APPLE_HYB
+ close(vol->fd);
+ v_destruct(vol);
+#endif /* APPLE_HYB */
+ return 0;
+ }
+
+ /* verify this is an HFS volume */
+
+ if (vol->mdb.drSigWord != 0x4244)
+ {
+#ifndef APPLE_HYB
+ close(vol->fd);
+#endif /* APPLE_HYB */
+ v_destruct(vol);
+
+ ERROR(EINVAL, "not a Macintosh HFS volume");
+ return 0;
+ }
+
+ /* do minimal consistency checks */
+
+ if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
+ {
+#ifndef APPLE_HYB
+ close(vol->fd);
+#endif /* APPLE_HYB */
+ v_destruct(vol);
+
+ ERROR(EINVAL, "bad volume allocation block size");
+ return 0;
+ }
+
+ if (vol->vlen == 0)
+ vol->vlen = vol->mdb.drAlBlSt +
+ vol->mdb.drNmAlBlks * (vol->mdb.drAlBlkSiz / HFS_BLOCKSZ) + 2;
+
+ /* read the volume bitmap and extents/catalog B*-tree headers */
+
+ if (l_readvbm(vol) < 0 ||
+ bt_readhdr(&vol->ext) < 0 ||
+ bt_readhdr(&vol->cat) < 0)
+ {
+#ifndef APPLE_HYB
+ close(vol->fd);
+#endif /* APPLE_HYB */
+ v_destruct(vol);
+ return 0;
+ }
+
+ if (! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
+ {
+ /* volume was not cleanly unmounted; scavenge free-space */
+
+ if (v_scavenge(vol) < 0)
+ {
+#ifndef APPLE_HYB
+ close(vol->fd);
+#endif /* APPLE_HYB */
+ v_destruct(vol);
+ return 0;
+ }
+ }
+
+ if (vol->flags & HFS_READONLY)
+ vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
+ else
+ vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
+
+ vol->prev = 0;
+ vol->next = hfs_mounts;
+
+ if (hfs_mounts)
+ hfs_mounts->prev = vol;
+
+ hfs_mounts = vol;
+ }
+
+ ++vol->refs;
+
+ return hfs_curvol = vol;
+}
+
+/*
+ * NAME: hfs->flush()
+ * DESCRIPTION: flush all pending changes to an HFS volume
+ */
+int hfs_flush(hfsvol *vol)
+{
+ hfsfile *file;
+
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ for (file = vol->files; file; file = file->next)
+ {
+ if (f_flush(file) < 0)
+ return -1;
+ }
+
+ if (v_flush(vol, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->flushall()
+ * DESCRIPTION: flush all pending changes to all mounted HFS volumes
+ */
+void hfs_flushall()
+{
+ hfsvol *vol;
+
+ for (vol = hfs_mounts; vol; vol = vol->next)
+ hfs_flush(vol);
+}
+
+/*
+ * NAME: hfs->umount()
+ * DESCRIPTION: close an HFS volume
+ */
+#ifdef APPLE_HYB
+/* extra argument used to alter the position of the extents/catalog files */
+int hfs_umount(hfsvol *vol, long end, long locked)
+#else
+int hfs_umount(hfsvol *vol)
+#endif /* APPLE_HYB */
+{
+ int result = 0;
+
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ if (--vol->refs)
+ return v_flush(vol, 0);
+
+ /* close all open files and directories */
+
+ while (vol->files)
+#ifdef APPLE_HYB
+ hfs_close(vol->files, 0, 0);
+#else
+ hfs_close(vol->files);
+#endif /* APPLE_HYB */
+
+ while (vol->dirs)
+ hfs_closedir(vol->dirs);
+
+#ifdef APPLE_HYB
+ if (end)
+ {
+ /* move extents and catalog to end of volume ... */
+ long vbmsz = (vol->vlen / vol->lpa + 4095) / 4096;
+
+ /* we are adding this "files" to the end of the ISO volume,
+ so calculate this address in HFS speak ... */
+/* end -= vol->mdb.drAlBlSt; */
+ end -= (vol->mdb.drAlBlSt + vol->hce->hfs_map_size);
+ end /= vol->lpa;
+
+ /* catalog file ... */
+ vol->ext.f.cat.u.fil.filExtRec[0].xdrStABN = end;
+ vol->mdb.drXTExtRec[0].xdrStABN = end;
+
+ /* move postition to start of extents file */
+ end += vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN;
+
+ /* extents file ... */
+ vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN = end;
+ vol->mdb.drCTExtRec[0].xdrStABN = end;
+
+ /* the volume bitmap is wrong as we have "moved" files
+ about - simple just set the whole lot (it's a readonly volume
+ anyway!) */
+ memset(vol->vbm, 0xff, vbmsz*HFS_BLOCKSZ);
+
+ /* set the free blocks to zero */
+ vol->mdb.drFreeBks = 0;
+
+ /* flag changes for flushing later */
+ vol->flags |= HFS_UPDATE_VBM;
+ vol->flags |= HFS_UPDATE_MDB;
+ vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
+ if (locked) {
+ vol->mdb.drAtrb |= HFS_ATRB_SLOCKED;
+ }
+ vol->ext.flags |= HFS_UPDATE_BTHDR;
+ vol->cat.flags |= HFS_UPDATE_BTHDR;
+ }
+#endif /* APPLE_HYB */
+
+ if (v_flush(vol, 1) < 0)
+ result = -1;
+
+#ifndef APPLE_HYB
+ if (close(vol->fd) < 0 && result == 0)
+ {
+ ERROR(errno, "error closing device");
+ result = -1;
+ }
+#endif /* APPLE_HYB */
+
+ 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 == hfs_curvol)
+ hfs_curvol = 0;
+
+ v_destruct(vol);
+
+ return result;
+}
+
+/*
+ * NAME: hfs->umountall()
+ * DESCRIPTION: unmount all mounted volumes
+ */
+void hfs_umountall()
+{
+ while (hfs_mounts)
+#ifdef APPLE_HYB
+ continue;
+#else
+ hfs_umount(hfs_mounts);
+#endif /* APPLE_HYB */
+}
+
+/*
+ * NAME: hfs->getvol()
+ * DESCRIPTION: return a pointer to a mounted volume
+ */
+hfsvol *hfs_getvol(char *name)
+{
+ hfsvol *vol;
+
+ if (name == 0)
+ return hfs_curvol;
+
+ for (vol = hfs_mounts; vol; vol = vol->next)
+ {
+ if (d_relstring(name, vol->mdb.drVN) == 0)
+ return vol;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->setvol()
+ * DESCRIPTION: change the current volume
+ */
+void hfs_setvol(hfsvol *vol)
+{
+ hfs_curvol = vol;
+}
+
+/*
+ * NAME: hfs->vstat()
+ * DESCRIPTION: return volume statistics
+ */
+int hfs_vstat(hfsvol *vol, hfsvolent *ent)
+{
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ strcpy(ent->name, vol->mdb.drVN);
+
+ ent->flags = (vol->flags & HFS_READONLY) ? HFS_ISLOCKED : 0;
+ ent->totbytes = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
+ ent->freebytes = vol->mdb.drFreeBks * vol->mdb.drAlBlkSiz;
+ ent->crdate = d_toutime(vol->mdb.drCrDate);
+ ent->mddate = d_toutime(vol->mdb.drLsMod);
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->format()
+ * DESCRIPTION: write a new filesystem
+ */
+#ifdef APPLE_HYB
+int hfs_format(hce_mem *hce, int pnum, char *vname)
+#else
+int hfs_format(char *path, int pnum, char *vname)
+#endif /* APPLE_HYB */
+{
+ hfsvol vol;
+ btree *ext = &vol.ext;
+ btree *cat = &vol.cat;
+ unsigned int vbmsz;
+ int i, result = 0;
+ block vbm[16];
+ char *map;
+
+ if (strchr(vname, ':'))
+ {
+ ERROR(EINVAL, "volume name may not contain colons");
+ return -1;
+ }
+
+ i = strlen(vname);
+ if (i < 1 || i > HFS_MAX_VLEN)
+ {
+ ERROR(EINVAL, "volume name must be 1-27 chars");
+ return -1;
+ }
+
+ vol.flags = 0;
+ vol.pnum = pnum;
+ vol.vstart = 0;
+ vol.vlen = 0;
+ vol.lpa = 0;
+ vol.vbm = vbm;
+ vol.cwd = HFS_CNID_ROOTDIR;
+
+ vol.refs = 0;
+ vol.files = 0;
+ vol.dirs = 0;
+ vol.prev = 0;
+ vol.next = 0;
+
+#ifndef APPLE_HYB
+ vol.fd = open(path, O_RDWR);
+ if (vol.fd < 0)
+ {
+ ERROR(errno, "error opening device for writing");
+ return -1;
+ }
+
+ if (l_lockvol(&vol) < 0)
+ {
+ close(vol.fd);
+ return -1;
+ }
+#endif /* APPLE_HYB */
+ if (pnum > 0)
+ {
+ if (l_readpm(&vol) < 0)
+ {
+ close(vol.fd);
+ return -1;
+ }
+ }
+ else /* determine size of entire device */
+ {
+#ifdef APPLE_HYB
+ vol.vlen = hce->hfs_vol_size;
+#else
+ unsigned long low, high, mid;
+ block b;
+
+ for (low = 0, high = 2879; b_readlb(&vol, high, &b) >= 0; high *= 2)
+ low = high;
+
+ while (low < high - 1)
+ {
+ mid = (low + high) / 2;
+
+ if (b_readlb(&vol, mid, &b) < 0)
+ high = mid;
+ else
+ low = mid;
+ }
+
+ vol.vlen = low + 1;
+#endif /* APPLE_HYB */
+ }
+
+ if (vol.vlen < 800 * 1024 / HFS_BLOCKSZ)
+ {
+#ifndef APPLE_HYB
+ close(vol.fd);
+#endif /* APPLE_HYB */
+
+ ERROR(EINVAL, "volume size must be >= 800K");
+ return -1;
+ }
+
+ /* initialize volume geometry */
+
+#ifdef APPLE_HYB
+ /* force lpa to be a multiple of 4 (i.e. 2048/512) - as calculated
+ earlier */
+ vol.lpa = hce->Csize/HFS_BLOCKSZ;
+#else
+ vol.lpa = 1 + vol.vlen / 65536;
+#endif /* APPLE_HYB */
+
+ vbmsz = (vol.vlen / vol.lpa + 4095) / 4096;
+
+ vol.mdb.drSigWord = 0x4244;
+ vol.mdb.drCrDate = d_tomtime(time(0));
+ vol.mdb.drLsMod = vol.mdb.drCrDate;
+ vol.mdb.drAtrb = 0;
+ vol.mdb.drNmFls = 0;
+ vol.mdb.drVBMSt = 3;
+ vol.mdb.drAllocPtr = 0;
+ vol.mdb.drNmAlBlks = (vol.vlen - 5 - vbmsz) / vol.lpa;
+ vol.mdb.drAlBlkSiz = vol.lpa * HFS_BLOCKSZ;
+ vol.mdb.drClpSiz = vol.mdb.drAlBlkSiz * 4;
+ vol.mdb.drAlBlSt = 3 + vbmsz;
+#ifdef APPLE_HYB
+ /* round up start block to a muliple of lpa - important later */
+/*vol.mdb.drAlBlSt = ((vol.mdb.drAlBlSt + vol.lpa - 1) / vol.lpa) * vol.lpa;
+*/
+ /* take in accout alignment of files wrt HFS volume start i.e we want
+ drAlBlSt plus hfs_map_size to me a multiple of lpa */
+ vol.mdb.drAlBlSt = ((vol.mdb.drAlBlSt + hce->hfs_map_size + vol.lpa - 1) / vol.lpa) * vol.lpa;
+ vol.mdb.drAlBlSt -= hce->hfs_map_size;
+#endif /* APPLE_HYB */
+ vol.mdb.drNxtCNID = HFS_CNID_ROOTDIR; /* modified later */
+ vol.mdb.drFreeBks = vol.mdb.drNmAlBlks;
+
+ strcpy(vol.mdb.drVN, vname);
+
+ vol.mdb.drVolBkUp = 0;
+ vol.mdb.drVSeqNum = 0;
+ vol.mdb.drWrCnt = 0;
+ vol.mdb.drXTClpSiz = vol.mdb.drNmAlBlks / 128 * vol.mdb.drAlBlkSiz;
+#ifdef APPLE_HYB
+ /* adjust size of extents/catalog upwards as we may have rounded up
+ allocation size */
+ i = 1 + vol.vlen / 65536;
+
+ vol.mdb.drXTClpSiz = (vol.mdb.drXTClpSiz * vol.lpa) / i;
+
+ /* round up to lpa size */
+ vol.mdb.drXTClpSiz = ((vol.mdb.drXTClpSiz + vol.mdb.drAlBlkSiz - 1) /
+ vol.mdb.drAlBlkSiz) * vol.mdb.drAlBlkSiz;
+
+ /* ignore above, use what we have already calculated ... */
+ vol.mdb.drXTClpSiz = hce->XTCsize;
+
+ /* make Catalog file CTC (default twice) as big - prevents further allocation
+ later which we don't want - this seems to work OK ... */
+/*vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * CTC; */
+ vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * hce->ctc_size;
+
+ /* we want to put things at the end of the volume later, so we'll
+ cheat here ... shouldn't matter, as we only need the volume read
+ only anyway (we won't be adding files later!) - leave some extra
+ space for the alternative MDB (in the last allocation block) */
+
+ vol.mdb.drNmAlBlks = vol.mdb.drFreeBks = vol.vlen / vol.lpa - 1;
+#else
+ vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz;
+#endif /* APPLE_HYB */
+ vol.mdb.drNmRtDirs = 0;
+ vol.mdb.drFilCnt = 0;
+ vol.mdb.drDirCnt = -1; /* incremented when root folder is created */
+
+ for (i = 0; i < 8; ++i)
+ vol.mdb.drFndrInfo[i] = 0;
+
+ vol.mdb.drVCSize = 0;
+ vol.mdb.drVBMCSize = 0;
+ vol.mdb.drCtlCSize = 0;
+
+ vol.mdb.drXTFlSize = 0;
+ vol.mdb.drCTFlSize = 0;
+
+ for (i = 0; i < 3; ++i)
+ {
+ vol.mdb.drXTExtRec[i].xdrStABN = 0;
+ vol.mdb.drXTExtRec[i].xdrNumABlks = 0;
+
+ vol.mdb.drCTExtRec[i].xdrStABN = 0;
+ vol.mdb.drCTExtRec[i].xdrNumABlks = 0;
+ }
+
+ /* initialize volume bitmap */
+
+ memset(vol.vbm, 0, sizeof(vbm));
+
+#ifdef APPLE_HYB
+ /* We don't want to write anything out at the moment, so we allocate
+ memory to hold the HFS "header" info and extents/catalog files.
+ Any reads/writes from/to these parts of the volume are trapped and
+ stored in memory. */
+
+ /* blocks up to the first unallocated block == HFS "header" info
+ This will be placed in the first 32kb of the ISO volume later */
+ hce->hfs_hdr_size = vol.mdb.drAlBlSt;
+
+ /* size of the extents and catalog files. This will be added
+ to the end of the ISO volume later */
+ hce->hfs_ce_size = vol.mdb.drXTClpSiz + vol.mdb.drCTClpSiz;
+
+ /* we also allocate space for the Desktop file and the alternative
+ MDB while we're here */
+ FREE(hce->hfs_ce);
+ hce->hfs_ce = ALLOC(unsigned char, (hce->hfs_ce_size + vol.mdb.drClpSiz
+ + vol.mdb.drAlBlkSiz));
+
+ /* allocate memory for the map and hdr */
+ FREE(hce->hfs_map);
+ hce->hfs_map = ALLOC(unsigned char, ((hce->hfs_hdr_size + hce->hfs_map_size)
+ *HFS_BLOCKSZ));
+
+ if (hce->hfs_ce == 0 || hce->hfs_map == 0)
+ {
+ ERROR(ENOMEM, 0);
+ result = -1;
+ }
+
+ /* hfs_hdr is immediately after the hfs_map */
+ hce->hfs_hdr = hce->hfs_map + hce->hfs_map_size*HFS_BLOCKSZ;
+
+ /* size needed in HFS_BLOCKSZ blocks for later use */
+ hce->hfs_ce_size /= HFS_BLOCKSZ;
+
+ /* note size of Desktop file */
+ hce->hfs_dt_size = vol.mdb.drClpSiz/HFS_BLOCKSZ;
+
+ /* total size of catalog/extents and desktop */
+ hce->hfs_tot_size = hce->hfs_ce_size + hce->hfs_dt_size;
+
+ /* alternative MDB in the last alocation block */
+ hce->hfs_alt_mdb = hce->hfs_ce + hce->hfs_tot_size*HFS_BLOCKSZ;
+
+ /* add the MDB to the total size */
+ hce->hfs_tot_size += vol.lpa;
+
+ /* store this info in the volume info */
+ vol.hce = hce;
+
+#endif /* APPLE_HYB */
+
+ /* create extents overflow file */
+
+ ext->f.vol = &vol;
+ ext->f.parid = 0;
+ strcpy(ext->f.name, "extents overflow");
+
+ ext->f.cat.cdrType = cdrFilRec;
+ /* ext->f.cat.cdrResrv2 */
+ ext->f.cat.u.fil.filFlags = 0;
+ ext->f.cat.u.fil.filTyp = 0;
+ /* ext->f.cat.u.fil.filUsrWds */
+ ext->f.cat.u.fil.filFlNum = HFS_CNID_EXT;
+ ext->f.cat.u.fil.filStBlk = 0;
+ ext->f.cat.u.fil.filLgLen = 0;
+ ext->f.cat.u.fil.filPyLen = 0;
+ ext->f.cat.u.fil.filRStBlk = 0;
+ ext->f.cat.u.fil.filRLgLen = 0;
+ ext->f.cat.u.fil.filRPyLen = 0;
+ ext->f.cat.u.fil.filCrDat = vol.mdb.drCrDate;
+ ext->f.cat.u.fil.filMdDat = vol.mdb.drLsMod;
+ ext->f.cat.u.fil.filBkDat = 0;
+ /* ext->f.cat.u.fil.filFndrInfo */
+ ext->f.cat.u.fil.filClpSize = 0;
+
+ for (i = 0; i < 3; ++i)
+ {
+ ext->f.cat.u.fil.filExtRec[i].xdrStABN = 0;
+ ext->f.cat.u.fil.filExtRec[i].xdrNumABlks = 0;
+
+ ext->f.cat.u.fil.filRExtRec[i].xdrStABN = 0;
+ ext->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+ /* ext->f.cat.u.fil.filResrv */
+ f_selectfork(&ext->f, 0);
+
+ ext->f.clump = vol.mdb.drXTClpSiz;
+ ext->f.flags = 0;
+
+ ext->f.prev = ext->f.next = 0;
+
+ n_init(&ext->hdrnd, ext, ndHdrNode, 0);
+
+ ext->hdrnd.nnum = 0;
+ ext->hdrnd.nd.ndNRecs = 3;
+ ext->hdrnd.roff[1] = 0x078;
+ ext->hdrnd.roff[2] = 0x0f8;
+ ext->hdrnd.roff[3] = 0x1f8;
+
+ memset(HFS_NODEREC(ext->hdrnd, 1), 0, 128);
+
+ ext->hdr.bthDepth = 0;
+ ext->hdr.bthRoot = 0;
+ ext->hdr.bthNRecs = 0;
+ ext->hdr.bthFNode = 0;
+ ext->hdr.bthLNode = 0;
+ ext->hdr.bthNodeSize = HFS_BLOCKSZ;
+ ext->hdr.bthKeyLen = 0x07;
+ ext->hdr.bthNNodes = 0;
+ ext->hdr.bthFree = 0;
+ for (i = 0; i < 76; ++i)
+ ext->hdr.bthResv[i] = 0;
+
+ map = ALLOC(char, HFS_MAP1SZ);
+ if (map == 0)
+ {
+ if (result == 0)
+ {
+ ERROR(ENOMEM, 0);
+ result = -1;
+ }
+ }
+ else
+ {
+ memset(map, 0, HFS_MAP1SZ);
+ BMSET(map, 0);
+ }
+
+ ext->map = map;
+ ext->mapsz = HFS_MAP1SZ;
+ ext->flags = HFS_UPDATE_BTHDR;
+ ext->compare = r_compareextkeys;
+
+ if (result == 0 && bt_space(ext, 1) < 0)
+ result = -1;
+
+ --ext->hdr.bthFree;
+
+ /* create catalog file */
+
+ cat->f.vol = &vol;
+ cat->f.parid = 0;
+ strcpy(cat->f.name, "catalog");
+
+ cat->f.cat.cdrType = cdrFilRec;
+ /* cat->f.cat.cdrResrv2 */
+ cat->f.cat.u.fil.filFlags = 0;
+ cat->f.cat.u.fil.filTyp = 0;
+ /* cat->f.cat.u.fil.filUsrWds */
+ cat->f.cat.u.fil.filFlNum = HFS_CNID_CAT;
+ cat->f.cat.u.fil.filStBlk = 0;
+ cat->f.cat.u.fil.filLgLen = 0;
+ cat->f.cat.u.fil.filPyLen = 0;
+ cat->f.cat.u.fil.filRStBlk = 0;
+ cat->f.cat.u.fil.filRLgLen = 0;
+ cat->f.cat.u.fil.filRPyLen = 0;
+ cat->f.cat.u.fil.filCrDat = vol.mdb.drCrDate;
+ cat->f.cat.u.fil.filMdDat = vol.mdb.drLsMod;
+ cat->f.cat.u.fil.filBkDat = 0;
+ /* cat->f.cat.u.fil.filFndrInfo */
+ cat->f.cat.u.fil.filClpSize = 0;
+
+ for (i = 0; i < 3; ++i)
+ {
+ cat->f.cat.u.fil.filExtRec[i].xdrStABN = 0;
+ cat->f.cat.u.fil.filExtRec[i].xdrNumABlks = 0;
+
+ cat->f.cat.u.fil.filRExtRec[i].xdrStABN = 0;
+ cat->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+ /* cat->f.cat.u.fil.filResrv */
+ f_selectfork(&cat->f, 0);
+
+ cat->f.clump = vol.mdb.drCTClpSiz;
+ cat->f.flags = 0;
+
+ cat->f.prev = cat->f.next = 0;
+
+ n_init(&cat->hdrnd, cat, ndHdrNode, 0);
+
+ cat->hdrnd.nnum = 0;
+ cat->hdrnd.nd.ndNRecs = 3;
+ cat->hdrnd.roff[1] = 0x078;
+ cat->hdrnd.roff[2] = 0x0f8;
+ cat->hdrnd.roff[3] = 0x1f8;
+
+ memset(HFS_NODEREC(cat->hdrnd, 1), 0, 128);
+
+ cat->hdr.bthDepth = 0;
+ cat->hdr.bthRoot = 0;
+ cat->hdr.bthNRecs = 0;
+ cat->hdr.bthFNode = 0;
+ cat->hdr.bthLNode = 0;
+ cat->hdr.bthNodeSize = HFS_BLOCKSZ;
+ cat->hdr.bthKeyLen = 0x25;
+ cat->hdr.bthNNodes = 0;
+ cat->hdr.bthFree = 0;
+ for (i = 0; i < 76; ++i)
+ cat->hdr.bthResv[i] = 0;
+
+ map = ALLOC(char, HFS_MAP1SZ);
+ if (map == 0)
+ {
+ if (result == 0)
+ {
+ ERROR(ENOMEM, 0);
+ result = -1;
+ }
+ }
+ else
+ {
+ memset(map, 0, HFS_MAP1SZ);
+ BMSET(map, 0);
+ }
+
+ cat->map = map;
+ cat->mapsz = HFS_MAP1SZ;
+ cat->flags = HFS_UPDATE_BTHDR;
+ cat->compare = r_comparecatkeys;
+
+ if (result == 0 && bt_space(cat, 1) < 0)
+ result = -1;
+
+ --cat->hdr.bthFree;
+
+ /* create root folder */
+
+ if (result == 0 && v_newfolder(&vol, HFS_CNID_ROOTPAR, vname) < 0)
+ result = -1;
+
+ vol.mdb.drNxtCNID = 16;
+
+ /* finish up */
+
+ if (result == 0)
+ {
+ block b;
+
+ /* write boot blocks */
+
+ memset(&b, 0, sizeof(b));
+ b_writelb(&vol, 0, &b);
+ b_writelb(&vol, 1, &b);
+
+ /* flush other disk state */
+
+ vol.flags |= HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB | HFS_UPDATE_VBM;
+
+ if (v_flush(&vol, 1) < 0)
+ result = -1;
+ }
+#ifndef APPLE_HYB
+ if (close(vol.fd) < 0 && result == 0)
+ {
+ ERROR(errno, "error closing device");
+ result = -1;
+ }
+#endif /* APPLE_HYB */
+ FREE(vol.ext.map);
+ FREE(vol.cat.map);
+
+ return result;
+}
+
+/* High-Level Directory Routines =========================================== */
+
+/*
+ * NAME: hfs->chdir()
+ * DESCRIPTION: change current HFS directory
+ */
+int hfs_chdir(hfsvol *vol, char *path)
+{
+ CatDataRec data;
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
+ return -1;
+
+ if (data.cdrType != cdrDirRec)
+ {
+ ERROR(ENOTDIR, 0);
+ return -1;
+ }
+
+ vol->cwd = data.u.dir.dirDirID;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->getcwd()
+ * DESCRIPTION: return the current working directory ID
+ */
+long hfs_getcwd(hfsvol *vol)
+{
+ if (v_getvol(&vol) < 0)
+ return 0;
+
+ return vol->cwd;
+}
+
+/*
+ * NAME: hfs->setcwd()
+ * DESCRIPTION: set the current working directory ID
+ */
+int hfs_setcwd(hfsvol *vol, long id)
+{
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ if (id == vol->cwd)
+ return 0;
+
+ /* make sure the directory exists */
+
+ if (v_getdthread(vol, id, 0, 0) <= 0)
+ return -1;
+
+ vol->cwd = id;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->dirinfo()
+ * DESCRIPTION: given a directory ID, return its (name and) parent ID
+ */
+int hfs_dirinfo(hfsvol *vol, long *id, char *name)
+{
+ CatDataRec thread;
+
+ if (v_getvol(&vol) < 0 ||
+ v_getdthread(vol, *id, &thread, 0) <= 0)
+ return -1;
+
+ *id = thread.u.dthd.thdParID;
+
+ if (name)
+ strcpy(name, thread.u.dthd.thdCName);
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->opendir()
+ * DESCRIPTION: prepare to read the contents of a directory
+ */
+hfsdir *hfs_opendir(hfsvol *vol, char *path)
+{
+ hfsdir *dir;
+ CatKeyRec key;
+ CatDataRec data;
+ unsigned char pkey[HFS_CATKEYLEN];
+
+ if (v_getvol(&vol) < 0)
+ return 0;
+
+ dir = ALLOC(hfsdir, 1);
+ if (dir == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return 0;
+ }
+
+ 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, 0, 0, 0) <= 0)
+ {
+ FREE(dir);
+ return 0;
+ }
+
+ if (data.cdrType != cdrDirRec)
+ {
+ FREE(dir);
+ ERROR(ENOTDIR, 0);
+ return 0;
+ }
+
+ dir->dirid = data.u.dir.dirDirID;
+ dir->vptr = 0;
+
+ r_makecatkey(&key, dir->dirid, "");
+ r_packcatkey(&key, pkey, 0);
+
+ if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
+ {
+ FREE(dir);
+ return 0;
+ }
+ }
+
+ dir->prev = 0;
+ dir->next = vol->dirs;
+
+ if (vol->dirs)
+ vol->dirs->prev = dir;
+
+ vol->dirs = dir;
+
+ return dir;
+}
+
+/*
+ * NAME: hfs->readdir()
+ * DESCRIPTION: return the next entry in the directory
+ */
+int hfs_readdir(hfsdir *dir, hfsdirent *ent)
+{
+ CatKeyRec key;
+ CatDataRec data;
+ unsigned char *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 == 0)
+ {
+ ERROR(ENOENT, "no more entries");
+ return -1;
+ }
+
+ if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 ||
+ v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
+ &data, cname, 0) < 0)
+ return -1;
+
+ r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
+
+ dir->vptr = vol->next;
+
+ return 0;
+ }
+
+ if (dir->n.rnum == -1)
+ {
+ ERROR(ENOENT, "no more entries");
+ return -1;
+ }
+
+ for (;;)
+ {
+ ++dir->n.rnum;
+
+ while (dir->n.rnum >= (int)dir->n.nd.ndNRecs)
+ {
+ dir->n.nnum = dir->n.nd.ndFLink;
+ if (dir->n.nnum == 0)
+ {
+ dir->n.rnum = -1;
+ ERROR(ENOENT, "no more entries");
+ return -1;
+ }
+
+ if (bt_getnode(&dir->n) < 0)
+ {
+ dir->n.rnum = -1;
+ return -1;
+ }
+
+ 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");
+ return -1;
+ }
+
+ r_unpackcatdata(HFS_RECDATA(ptr), &data);
+
+ switch (data.cdrType)
+ {
+ case cdrDirRec:
+ case cdrFilRec:
+ r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
+ return 0;
+
+ case cdrThdRec:
+ case cdrFThdRec:
+ break;
+
+ default:
+ dir->n.rnum = -1;
+
+ ERROR(EIO, "unexpected directory entry found");
+ 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, char *path)
+{
+ hfsfile *file;
+
+ if (v_getvol(&vol) < 0)
+ return 0;
+
+ file = ALLOC(hfsfile, 1);
+ if (file == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return 0;
+ }
+
+ if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0)
+ {
+ FREE(file);
+ return 0;
+ }
+
+ if (file->cat.cdrType != cdrFilRec)
+ {
+ FREE(file);
+ ERROR(EISDIR, 0);
+ return 0;
+ }
+
+ file->vol = vol;
+ file->clump = file->cat.u.fil.filClpSize;
+ file->flags = 0;
+
+ f_selectfork(file, 0);
+
+ file->prev = 0;
+ file->next = vol->files;
+
+ if (vol->files)
+ vol->files->prev = file;
+
+ vol->files = file;
+
+ return file;
+}
+
+/*
+ * NAME: hfs->setfork()
+ * DESCRIPTION: select file fork for I/O operations
+ */
+int hfs_setfork(hfsfile *file, int ffork)
+{
+ int result = 0;
+
+ if (! (file->vol->flags & HFS_READONLY) &&
+ f_trunc(file) < 0)
+ result = -1;
+
+ f_selectfork(file, ffork);
+
+ 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
+ */
+long hfs_read(hfsfile *file, void *buf, unsigned long len)
+{
+ unsigned long *lglen, count;
+ unsigned char *ptr = buf;
+
+ f_getptrs(file, &lglen, 0, 0);
+
+ if (file->pos + len > *lglen)
+ len = *lglen - file->pos;
+
+ count = len;
+ while (count)
+ {
+ block b;
+ unsigned long bnum, offs, chunk;
+
+ bnum = file->pos / HFS_BLOCKSZ;
+ offs = file->pos % HFS_BLOCKSZ;
+
+ chunk = HFS_BLOCKSZ - offs;
+ if (chunk > count)
+ chunk = count;
+
+ if (f_getblock(file, bnum, &b) < 0)
+ return -1;
+
+ memcpy(ptr, b + offs, chunk);
+ ptr += chunk;
+
+ file->pos += chunk;
+ count -= chunk;
+ }
+
+ return len;
+}
+
+/*
+ * NAME: hfs->write()
+ * DESCRIPTION: write to an open file
+ */
+long hfs_write(hfsfile *file, void *buf, unsigned long len)
+{
+ unsigned long *lglen, *pylen, count;
+ unsigned char *ptr = buf;
+
+ if (file->vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ f_getptrs(file, &lglen, &pylen, 0);
+
+ count = len;
+
+ /* set flag to update (at least) the modification time */
+
+ if (count)
+ {
+ file->cat.u.fil.filMdDat = d_tomtime(time(0));
+ file->flags |= HFS_UPDATE_CATREC;
+ }
+
+ while (count)
+ {
+ block b;
+ unsigned long bnum, offs, chunk;
+
+ bnum = file->pos / HFS_BLOCKSZ;
+ offs = file->pos % HFS_BLOCKSZ;
+
+ chunk = HFS_BLOCKSZ - offs;
+ if (chunk > count)
+ chunk = count;
+
+ if (file->pos + chunk > *pylen)
+ {
+ if (bt_space(&file->vol->ext, 1) < 0 ||
+ f_alloc(file) < 0)
+ return -1;
+ }
+#ifndef APPLE_HYB
+ /* Ignore this part as we are always writing new files to an empty disk
+ i.e. offs will always be 0 */
+
+ if (offs > 0 || chunk < HFS_BLOCKSZ)
+ {
+ if (f_getblock(file, bnum, &b) < 0)
+ return -1;
+ }
+#endif /* APPLE_HYB */
+ memcpy(b + offs, ptr, chunk);
+ ptr += chunk;
+
+ if (f_putblock(file, bnum, &b) < 0)
+ return -1;
+
+ file->pos += chunk;
+ count -= chunk;
+
+ if (file->pos > *lglen)
+ *lglen = file->pos;
+ }
+
+ return len;
+}
+
+/*
+ * NAME: hfs->truncate()
+ * DESCRIPTION: truncate an open file
+ */
+int hfs_truncate(hfsfile *file, unsigned long len)
+{
+ unsigned long *lglen;
+
+ f_getptrs(file, &lglen, 0, 0);
+
+ if (*lglen > len)
+ {
+ if (file->vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ *lglen = len;
+
+ file->cat.u.fil.filMdDat = d_tomtime(time(0));
+ file->flags |= HFS_UPDATE_CATREC;
+
+ if (file->pos > len)
+ file->pos = len;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->lseek()
+ * DESCRIPTION: change file seek pointer
+ */
+long hfs_lseek(hfsfile *file, long offset, int from)
+{
+ unsigned long *lglen;
+ long newpos;
+
+ f_getptrs(file, &lglen, 0, 0);
+
+ switch (from)
+ {
+ case SEEK_SET:
+ newpos = offset;
+ break;
+
+ case SEEK_CUR:
+ newpos = file->pos + offset;
+ break;
+
+ case SEEK_END:
+ newpos = *lglen + offset;
+ break;
+
+ default:
+ ERROR(EINVAL, 0);
+ return -1;
+ }
+
+ if (newpos < 0)
+ newpos = 0;
+ else if (newpos > *lglen)
+ newpos = *lglen;
+
+ file->pos = newpos;
+
+ return newpos;
+}
+
+/*
+ * NAME: hfs->close()
+ * DESCRIPTION: close a file
+ */
+#ifdef APPLE_HYB
+/* extra args are used to set the start of the forks in the ISO volume */
+int hfs_close(hfsfile *file, long dext, long rext)
+{
+ int offset;
+#else
+int hfs_close(hfsfile *file)
+{
+#endif /* APPLE_HYB */
+ hfsvol *vol = file->vol;
+ int result = 0;
+
+ if (f_trunc(file) < 0 ||
+ f_flush(file) < 0)
+ result = -1;
+
+#ifdef APPLE_HYB
+ /* "start" of file is relative to the first available block */
+ offset = vol->hce->hfs_hdr_size + vol->hce->hfs_map_size;
+ /* update the "real" starting extent and re-flush the file */
+ if (dext)
+ file->cat.u.fil.filExtRec[0].xdrStABN = (dext - offset)/vol->lpa;
+
+ if (rext)
+ file->cat.u.fil.filRExtRec[0].xdrStABN = (rext - offset)/vol->lpa;
+
+ if (dext || rext)
+ file->flags |= HFS_UPDATE_CATREC;
+
+ if (f_flush(file) < 0)
+ result = -1;
+#endif /*APPLE_HYB */
+
+ 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, char *path, hfsdirent *ent)
+{
+ CatDataRec data;
+ long parid;
+ char name[HFS_MAX_FLEN + 1];
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
+ return -1;
+
+ r_unpackdirent(parid, name, &data, ent);
+
+ return 0;
+}
+
+/*
+ * 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->setattr()
+ * DESCRIPTION: change a file's attributes
+ */
+int hfs_setattr(hfsvol *vol, char *path, hfsdirent *ent)
+{
+ CatDataRec data;
+ node n;
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, path, &data, 0, 0, &n) <= 0)
+ return -1;
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ r_packdirent(&data, ent);
+
+ if (v_putcatrec(&data, &n) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->fsetattr()
+ * DESCRIPTION: change an open file's attributes
+ */
+int hfs_fsetattr(hfsfile *file, hfsdirent *ent)
+{
+ if (file->vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ r_packdirent(&file->cat, ent);
+
+ file->flags |= HFS_UPDATE_CATREC;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->mkdir()
+ * DESCRIPTION: create a new directory
+ */
+int hfs_mkdir(hfsvol *vol, char *path)
+{
+ CatDataRec data;
+ long parid;
+ char name[HFS_MAX_FLEN + 1];
+ int found;
+
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ found = v_resolve(&vol, path, &data, &parid, name, 0);
+ if (found < 0 || parid == 0)
+ return -1;
+ else if (found)
+ {
+ ERROR(EEXIST, 0);
+ return -1;
+ }
+
+ if (parid == HFS_CNID_ROOTPAR)
+ {
+ ERROR(EINVAL, 0);
+ return -1;
+ }
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ if (v_newfolder(vol, parid, name) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->rmdir()
+ * DESCRIPTION: delete an empty directory
+ */
+int hfs_rmdir(hfsvol *vol, char *path)
+{
+ CatKeyRec key;
+ CatDataRec data;
+ long parid;
+ char name[HFS_MAX_FLEN + 1];
+ unsigned char pkey[HFS_CATKEYLEN];
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
+ return -1;
+
+ if (data.cdrType != cdrDirRec)
+ {
+ ERROR(ENOTDIR, 0);
+ return -1;
+ }
+
+ if (data.u.dir.dirVal != 0)
+ {
+ ERROR(ENOTEMPTY, 0);
+ return -1;
+ }
+
+ if (parid == HFS_CNID_ROOTPAR)
+ {
+ ERROR(EINVAL, 0);
+ return -1;
+ }
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ /* delete directory record */
+
+ r_makecatkey(&key, parid, name);
+ r_packcatkey(&key, pkey, 0);
+
+ if (bt_delete(&vol->cat, pkey) < 0)
+ return -1;
+
+ /* delete thread record */
+
+ r_makecatkey(&key, data.u.dir.dirDirID, "");
+ r_packcatkey(&key, pkey, 0);
+
+ if (bt_delete(&vol->cat, pkey) < 0 ||
+ v_adjvalence(vol, parid, 1, -1) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->create()
+ * DESCRIPTION: create a new file
+ */
+int hfs_create(hfsvol *vol, char *path, char *type, char *creator)
+{
+ CatKeyRec key;
+ CatDataRec data;
+ long id, parid;
+ char name[HFS_MAX_FLEN + 1];
+ unsigned char record[HFS_CATRECMAXLEN];
+ int found, i, reclen;
+
+ if (v_getvol(&vol) < 0)
+ return -1;
+
+ found = v_resolve(&vol, path, &data, &parid, name, 0);
+ if (found < 0 || parid == 0)
+ return -1;
+ else if (found)
+ {
+ ERROR(EEXIST, 0);
+ return -1;
+ }
+
+ if (parid == HFS_CNID_ROOTPAR)
+ {
+ ERROR(EINVAL, 0);
+ return -1;
+ }
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ /* create file `name' in parent `parid' */
+
+ if (bt_space(&vol->cat, 1) < 0)
+ return -1;
+
+ id = vol->mdb.drNxtCNID++;
+ vol->flags |= HFS_UPDATE_MDB;
+
+ /* create file record */
+
+ data.cdrType = cdrFilRec;
+ data.cdrResrv2 = 0;
+
+ data.u.fil.filFlags = 0;
+ data.u.fil.filTyp = 0;
+
+ memset(&data.u.fil.filUsrWds, 0, sizeof(data.u.fil.filUsrWds));
+
+ data.u.fil.filUsrWds.fdType = d_getl((unsigned char *) type);
+ data.u.fil.filUsrWds.fdCreator = d_getl((unsigned char *) creator);
+
+ data.u.fil.filFlNum = id;
+ data.u.fil.filStBlk = 0;
+ data.u.fil.filLgLen = 0;
+ data.u.fil.filPyLen = 0;
+ data.u.fil.filRStBlk = 0;
+ data.u.fil.filRLgLen = 0;
+ data.u.fil.filRPyLen = 0;
+ data.u.fil.filCrDat = d_tomtime(time(0));
+ data.u.fil.filMdDat = data.u.fil.filCrDat;
+ data.u.fil.filBkDat = 0;
+
+ memset(&data.u.fil.filFndrInfo, 0, sizeof(data.u.fil.filFndrInfo));
+
+ data.u.fil.filClpSize = 0;
+
+ for (i = 0; i < 3; ++i)
+ {
+ data.u.fil.filExtRec[i].xdrStABN = 0;
+ data.u.fil.filExtRec[i].xdrNumABlks = 0;
+
+ data.u.fil.filRExtRec[i].xdrStABN = 0;
+ data.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+
+ data.u.fil.filResrv = 0;
+
+ r_makecatkey(&key, parid, name);
+ r_packcatkey(&key, record, &reclen);
+ r_packcatdata(&data, HFS_RECDATA(record), &reclen);
+
+ if (bt_insert(&vol->cat, record, reclen) < 0 ||
+ v_adjvalence(vol, parid, 0, 1) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->delete()
+ * DESCRIPTION: remove both forks of a file
+ */
+int hfs_delete(hfsvol *vol, char *path)
+{
+ hfsfile file;
+ CatKeyRec key;
+ unsigned char pkey[HFS_CATKEYLEN];
+ int found;
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, path, &file.cat, &file.parid, file.name, 0) <= 0)
+ return -1;
+
+ if (file.cat.cdrType != cdrFilRec)
+ {
+ ERROR(EISDIR, 0);
+ return -1;
+ }
+
+ if (file.parid == HFS_CNID_ROOTPAR)
+ {
+ ERROR(EINVAL, 0);
+ return -1;
+ }
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ /* free disk blocks */
+
+ file.vol = vol;
+ file.flags = 0;
+
+ file.cat.u.fil.filLgLen = 0;
+ file.cat.u.fil.filRLgLen = 0;
+
+ f_selectfork(&file, 0);
+ if (f_trunc(&file) < 0)
+ return -1;
+
+ f_selectfork(&file, 1);
+ if (f_trunc(&file) < 0)
+ return -1;
+
+ /* delete file record */
+
+ r_makecatkey(&key, file.parid, file.name);
+ r_packcatkey(&key, pkey, 0);
+
+ if (bt_delete(&vol->cat, pkey) < 0 ||
+ v_adjvalence(vol, file.parid, 0, -1) < 0)
+ return -1;
+
+ /* delete file thread, if any */
+
+ found = v_getfthread(vol, file.cat.u.fil.filFlNum, 0, 0);
+ if (found < 0)
+ return -1;
+
+ if (found)
+ {
+ r_makecatkey(&key, file.cat.u.fil.filFlNum, "");
+ r_packcatkey(&key, pkey, 0);
+
+ if (bt_delete(&vol->cat, pkey) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: hfs->rename()
+ * DESCRIPTION: change the name of and/or move a file or directory
+ */
+int hfs_rename(hfsvol *vol, char *srcpath, char *dstpath)
+{
+ hfsvol *srcvol;
+ CatDataRec src, dst;
+ long srcid, dstid;
+ CatKeyRec key;
+ char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1];
+ unsigned char record[HFS_CATRECMAXLEN];
+ int found, isdir, moving, reclen;
+ node n;
+
+ if (v_getvol(&vol) < 0 ||
+ v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0)
+ return -1;
+
+ isdir = (src.cdrType == cdrDirRec);
+ srcvol = vol;
+
+ found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0);
+ if (found < 0)
+ return -1;
+
+ if (vol != srcvol)
+ {
+ ERROR(EINVAL, "can't move across volumes");
+ return -1;
+ }
+
+ if (dstid == 0)
+ {
+ ERROR(ENOENT, "bad destination path");
+ return -1;
+ }
+
+ if (found &&
+ dst.cdrType == cdrDirRec &&
+ dst.u.dir.dirDirID != src.u.dir.dirDirID)
+ {
+ dstid = dst.u.dir.dirDirID;
+ strcpy(dstname, srcname);
+
+ found = v_catsearch(vol, dstid, dstname, 0, 0, 0);
+ if (found < 0)
+ return -1;
+ }
+
+ moving = (srcid != dstid);
+
+ if (found)
+ {
+ char *ptr;
+
+ ptr = strrchr(dstpath, ':');
+ if (ptr == 0)
+ ptr = dstpath;
+ else
+ ++ptr;
+
+ if (*ptr)
+ strcpy(dstname, ptr);
+
+ if (! moving && strcmp(srcname, dstname) == 0)
+ return 0; /* source and destination are the same */
+
+ if (moving || d_relstring(srcname, dstname))
+ {
+ ERROR(EEXIST, "can't use destination name");
+ return -1;
+ }
+ }
+
+ /* can't move anything into the root directory's parent */
+
+ if (moving && dstid == HFS_CNID_ROOTPAR)
+ {
+ ERROR(EINVAL, "can't move above root directory");
+ return -1;
+ }
+
+ if (moving && isdir)
+ {
+ long id;
+
+ /* can't move root directory anywhere */
+
+ if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR)
+ {
+ ERROR(EINVAL, "can't move root directory");
+ return -1;
+ }
+
+ /* make sure we aren't trying to move a directory inside itself */
+
+ for (id = dstid; id != HFS_CNID_ROOTDIR; id = dst.u.dthd.thdParID)
+ {
+ if (id == src.u.dir.dirDirID)
+ {
+ ERROR(EINVAL, "can't move directory inside itself");
+ return -1;
+ }
+
+ if (v_getdthread(vol, id, &dst, 0) <= 0)
+ return -1;
+ }
+ }
+
+ if (vol->flags & HFS_READONLY)
+ {
+ ERROR(EROFS, 0);
+ return -1;
+ }
+
+ /* change volume name */
+
+ if (dstid == HFS_CNID_ROOTPAR)
+ {
+ if (strlen(dstname) > HFS_MAX_VLEN)
+ {
+ ERROR(ENAMETOOLONG, 0);
+ return -1;
+ }
+
+ strcpy(vol->mdb.drVN, dstname);
+ vol->flags |= HFS_UPDATE_MDB;
+ }
+
+ /* remove source record */
+
+ r_makecatkey(&key, srcid, srcname);
+ r_packcatkey(&key, record, 0);
+
+ if (bt_delete(&vol->cat, record) < 0)
+ return -1;
+
+ /* insert destination record */
+
+ r_makecatkey(&key, dstid, dstname);
+ r_packcatkey(&key, record, &reclen);
+ r_packcatdata(&src, HFS_RECDATA(record), &reclen);
+
+ if (bt_insert(&vol->cat, record, reclen) < 0)
+ return -1;
+
+ /* update thread record */
+
+ if (isdir)
+ {
+ if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0)
+ return -1;
+
+ dst.u.dthd.thdParID = dstid;
+ strcpy(dst.u.dthd.thdCName, dstname);
+
+ if (v_putcatrec(&dst, &n) < 0)
+ return -1;
+ }
+ else
+ {
+ found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n);
+ if (found < 0)
+ return -1;
+
+ if (found)
+ {
+ dst.u.fthd.fthdParID = dstid;
+ strcpy(dst.u.fthd.fthdCName, dstname);
+
+ if (v_putcatrec(&dst, &n) < 0)
+ return -1;
+ }
+ }
+
+ /* update directory valences */
+
+ if (moving)
+ {
+ if (v_adjvalence(vol, srcid, isdir, -1) < 0 ||
+ v_adjvalence(vol, dstid, isdir, 1) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+#ifdef APPLE_HYB
+/*
+ * NAME: hfs->hfs_get_drAllocPtr()
+ * DESCRIPTION: get the current start of next allocation search
+ */
+unsigned short
+hfs_get_drAllocPtr(hfsfile *file)
+{
+ return(file->vol->mdb.drAllocPtr);
+}
+
+/*
+ * NAME: hfs->hfs_set_drAllocPtr()
+ * DESCRIPTION: set the current start of next allocation search
+ */
+#ifdef PROTOTYPES
+int
+hfs_set_drAllocPtr(hfsfile *file, unsigned short drAllocPtr, int size)
+#else
+int
+hfs_set_drAllocPtr(hfsfile *file, unsigned short drAllocPtr, int size)
+#endif
+{
+ hfsvol *vol = file->vol;
+ int result = 0;
+
+ /* truncate the current fork */
+ if (f_trunc(file) < 0 ||
+ f_flush(file) < 0)
+ result = -1;
+
+ /* convert the fork size into allocation blocks */
+ size = (size + vol->mdb.drAlBlkSiz - 1)/vol->mdb.drAlBlkSiz;
+
+ /* set the start of next allocation search to be after this fork */
+ vol->mdb.drAllocPtr = drAllocPtr + size;
+
+ vol->flags |= HFS_UPDATE_MDB;
+
+ return result;
+}
+
+/*
+ * NAME: hfs->vsetbless()
+ * DESCRIPTION: set blessed folder
+ *
+ * adapted from vsetattr() from v3.2.6
+ */
+#ifdef PROTOTYPES
+void
+hfs_vsetbless(hfsvol *vol, unsigned long cnid)
+#else
+void
+hfs_vsetbless(hfsvol *vol, unsigned long cnid)
+#endif
+{
+ vol->mdb.drFndrInfo[0] = cnid;
+
+ vol->flags |= HFS_UPDATE_MDB;
+}
+#endif /* APPLE_HYB */
diff --git a/libhfs_iso/hfs.h b/libhfs_iso/hfs.h
new file mode 100644
index 0000000..f2c9d96
--- /dev/null
+++ b/libhfs_iso/hfs.h
@@ -0,0 +1,208 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)hfs.h 1.4 01/11/01 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef HFS_H
+#define HFS_H
+
+#include <timedefs.h>
+#include <standard.h>
+
+#ifdef APPLE_HYB
+#include "hybrid.h"
+
+/* don't need device locking for mkhybrid */
+#ifndef NODEVLOCKS
+#define NODEVLOCKS
+#endif /* NODEVLOCKS */
+
+#endif /* APPLE_HYB */
+
+# define HFS_BLOCKSZ 512
+# 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 */
+ int flags; /* volume flags */
+ unsigned long totbytes; /* total bytes on volume */
+ unsigned long freebytes; /* free bytes on volume */
+ time_t crdate; /* volume creation date */
+ time_t mddate; /* last volume modification date */
+} hfsvolent;
+
+/* taken from v3.2.6 */
+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;
+
+ /* mkhybrid extra */
+ signed short view; /* Folder's view */
+
+ struct {
+ signed short v; /* Scoll vertical position */
+ signed short h; /* Scoll horizontal position */
+ } frscroll;
+ } dir;
+ } u;
+} hfsdirent;
+
+
+# define HFS_ISDIR 0x01
+# define HFS_ISLOCKED 0x02
+
+# 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 char *hfs_error;
+/*extern unsigned char hfs_charorder[];*/
+
+#ifdef APPLE_HYB
+hfsvol *hfs_mount(hce_mem *, int, int);
+#else
+hfsvol *hfs_mount(char *, int, int);
+#endif /* APPLE_HYB */
+
+int hfs_flush(hfsvol *);
+void hfs_flushall(void);
+#ifdef APPLE_HYB
+int hfs_umount(hfsvol *, long, long);
+#else
+int hfs_umount(hfsvol *);
+#endif /* APPLE_HYB */
+void hfs_umountall(void);
+hfsvol *hfs_getvol(char *);
+void hfs_setvol(hfsvol *);
+
+int hfs_vstat(hfsvol *, hfsvolent *);
+#ifdef APPLE_HYB
+int hfs_format(hce_mem *, int, char *);
+#else
+int hfs_format(char *, int, char *);
+#endif /* APPLE_HYB */
+
+int hfs_chdir(hfsvol *, char *);
+long hfs_getcwd(hfsvol *);
+int hfs_setcwd(hfsvol *, long);
+int hfs_dirinfo(hfsvol *, long *, char *);
+
+hfsdir *hfs_opendir(hfsvol *, char *);
+int hfs_readdir(hfsdir *, hfsdirent *);
+int hfs_closedir(hfsdir *);
+
+hfsfile *hfs_open(hfsvol *, char *);
+int hfs_setfork(hfsfile *, int);
+int hfs_getfork(hfsfile *);
+long hfs_read(hfsfile *, void *, unsigned long);
+long hfs_write(hfsfile *, void *, unsigned long);
+int hfs_truncate(hfsfile *, unsigned long);
+long hfs_lseek(hfsfile *, long, int);
+#ifdef APPLE_HYB
+int hfs_close(hfsfile *, long, long);
+#else
+int hfs_close(hfsfile *);
+#endif /* APPLE_HYB */
+
+int hfs_stat(hfsvol *, char *, hfsdirent *);
+int hfs_fstat(hfsfile *, hfsdirent *);
+int hfs_setattr(hfsvol *, char *, hfsdirent *);
+int hfs_fsetattr(hfsfile *, hfsdirent *);
+
+int hfs_mkdir(hfsvol *, char *);
+int hfs_rmdir(hfsvol *, char *);
+
+int hfs_create(hfsvol *, char *, char *, char *);
+int hfs_delete(hfsvol *, char *);
+
+int hfs_rename(hfsvol *, char *, char *);
+
+int f_trunc(hfsfile *file);
+
+#ifdef APPLE_HYB
+unsigned short hfs_get_drAllocPtr(hfsfile *);
+int hfs_set_drAllocPtr(hfsfile *, unsigned short, int size);
+void hfs_vsetbless(hfsvol *, unsigned long);
+#endif /* APPLE_HYB */
+
+#endif
diff --git a/libhfs_iso/hybrid.h b/libhfs_iso/hybrid.h
new file mode 100644
index 0000000..01b83a6
--- /dev/null
+++ b/libhfs_iso/hybrid.h
@@ -0,0 +1,67 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)hybrid.h 1.3 02/10/04 joerg */
+/*
+** hybrid.h: extra info needed by libhfs and mkisofs
+**
+** James Pearson 15/9/97
+*/
+
+#ifndef _HYBRID_H
+
+/*
+ * The following three variables can be overridden at run time
+ * by using the -hfs-parms option i.e. to use the following defaults
+ * you could use: -hfs-parms CTC=2,CTC_LOOP=4,MAX_XTCSIZE=4194304
+ * i.e. to change just MAX_XTCSIZE to 2Mb use:
+ * -hfs-parms MAX_XTCSIZE=2097152
+ */
+
+#define CTC 2 /* factor to increase initial Catalog file
+ size to prevent the file growing */
+#define CTC_LOOP 4 /* number of attemps before we give up
+ trying to create the volume */
+
+#define MAX_XTCSIZE 4*1024*1024 /* the maximum size of the Catalog file -
+ as the size of the Catalog file is linked
+ to the size of the volume, multi-gigabyte
+ volumes create very large Catalog and
+ Extent files - 4Mb is the size calculated
+ for a 1Gb volume - which is probably
+ overkill, but seems to be OK */
+
+#define HCE_ERROR -9999 /* dummy errno value for Catalog file
+ size problems */
+
+#define HFS_MAP_SIZE 16 /* size of HFS partition maps (8Kb) */
+
+typedef struct {
+ int hfs_ce_size; /* extents/catalog size in HFS blks */
+ int hfs_hdr_size; /* vol header size in HFS blks */
+ int hfs_dt_size; /* Desktop file size in HFS blks */
+ int hfs_tot_size; /* extents/catalog/dt size in HFS blks */
+ int hfs_map_size; /* size of partition maps in HFS blks */
+ unsigned long hfs_vol_size; /* size of volume in HFS blks */
+ unsigned char *hfs_ce; /* mem copy of extents/catalog files */
+ unsigned char *hfs_hdr; /* mem copy of vol header */
+ unsigned char *hfs_alt_mdb; /* location of alternate MDB */
+ unsigned char *hfs_map; /* location of partiton_maps */
+ int Csize; /* size of allocation unit (bytes) */
+ int XTCsize; /* def size of catalog/extents files (bytes) */
+ int max_XTCsize; /* max size of catalog/extents files (bytes) */
+ int ctc_size; /* factor to increase Catalog file size */
+ char *error; /* HFS error message */
+} hce_mem;
+
+#define _HYBRID_H
+#endif /* _HYBRID_H */
diff --git a/libhfs_iso/internal.h b/libhfs_iso/internal.h
new file mode 100644
index 0000000..ee79b0c
--- /dev/null
+++ b/libhfs_iso/internal.h
@@ -0,0 +1,369 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)internal.h 1.2 01/11/01 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <timedefs.h>
+#include <standard.h>
+
+# include "hfs.h"
+
+# define ERROR(code, str) (hfs_error = (str), errno = (code))
+
+# 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) {if (ptr) free((void *) ptr) ;}
+
+# define REALLOC(ptr, type, n) \
+ ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n))))
+# define REALLOCX(ptr, type, n) \
+ ((n) ? REALLOC(type, n) : (FREE(ptr), (type *) 0))
+
+# define BMTST(bm, num) \
+ (((char *) (bm))[(num) >> 3] & (0x80 >> ((num) & 0x07)))
+# define BMSET(bm, num) \
+ (((char *) (bm))[(num) >> 3] |= (0x80 >> ((num) & 0x07)))
+# define BMCLR(bm, num) \
+ (((char *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07)))
+
+typedef unsigned char block[HFS_BLOCKSZ];
+
+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 {
+ 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;
+
+# define HFS_MAP1SZ 256
+# define HFS_MAPXSZ 492
+
+# define HFS_NODEREC(nd, rnum) ((nd).data + (nd).roff[rnum])
+
+# define HFS_RECKEYLEN(ptr) (*(unsigned char *) (ptr))
+# define HFS_RECKEYSKIP(ptr) ((1 + HFS_RECKEYLEN(ptr) + 1) & ~1)
+# define HFS_RECDATA(ptr) ((ptr) + HFS_RECKEYSKIP(ptr))
+
+# define HFS_CATDATALEN sizeof(CatDataRec)
+# define HFS_EXTDATALEN sizeof(ExtDataRec)
+
+# define HFS_CATKEYLEN sizeof(CatKeyRec)
+# define HFS_EXTKEYLEN sizeof(ExtKeyRec)
+
+# define HFS_CATRECMAXLEN (HFS_CATKEYLEN + HFS_CATDATALEN)
+# define HFS_EXTRECMAXLEN (HFS_EXTKEYLEN + HFS_EXTDATALEN)
+
+# define HFS_MAXRECLEN HFS_CATRECMAXLEN
+
+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; /* rightmost 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 drVCSize; /* size (in blocks) of volume cache */
+ UInteger drVBMCSize; /* size (in blocks) of volume bitmap cache */
+ UInteger drCtlCSize; /* size (in blocks) of common volume cache */
+ 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;
+
+# 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_COPYPROT (1 << 14)
+# define HFS_ATRB_SLOCKED (1 << 15)
+
+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;
+
+struct _hfsfile_ {
+ struct _hfsvol_ *vol; /* pointer to volume descriptor */
+ 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 */
+ unsigned long clump; /* file's clump size, for allocation */
+ int flags; /* bit flags */
+
+ struct _hfsfile_ *prev;
+ struct _hfsfile_ *next;
+};
+
+# define HFS_UPDATE_CATREC 0x01
+
+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;
+
+# define HFS_MAXRECS 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_MAXRECS + 1]; /* record offsets */
+ block data; /* raw contents of node */
+} node;
+
+enum {
+ ndIndxNode = 0x00,
+ ndHdrNode = 0x01,
+ ndMapNode = 0x02,
+ ndLeafNode = 0xff
+};
+
+struct _hfsdir_ {
+ struct _hfsvol_ *vol; /* associated volume */
+ 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 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;
+
+typedef struct _btree_ {
+ hfsfile f; /* subset file information */
+ node hdrnd; /* header node */
+ BTHdrRec hdr; /* header record */
+ char *map; /* usage bitmap */
+ unsigned long mapsz; /* number of bytes in bitmap */
+ int flags; /* bit flags */
+
+ int (*compare)(unsigned char *, unsigned char *);
+ /* key comparison function */
+} btree;
+
+# define HFS_UPDATE_BTHDR 0x01
+
+struct _hfsvol_ {
+ int fd; /* volume's open file descriptor */
+ int flags; /* bit flags */
+
+#ifdef APPLE_HYB
+ hce_mem *hce; /* Extras needed by libhfs/mkisofs */
+#endif /* APPLE_HYB */
+
+ 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 */
+
+ MDB mdb; /* master directory block */
+ block *vbm; /* volume bit map */
+ btree ext; /* B*-tree control block for extents overflow file */
+ btree cat; /* B*-tree control block for catalog file */
+ 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_READONLY 0x01
+
+# define HFS_UPDATE_MDB 0x10
+# define HFS_UPDATE_ALTMDB 0x20
+# define HFS_UPDATE_VBM 0x40
+
+extern hfsvol *hfs_mounts;
+extern hfsvol *hfs_curvol;
diff --git a/libhfs_iso/low.c b/libhfs_iso/low.c
new file mode 100644
index 0000000..94cba83
--- /dev/null
+++ b/libhfs_iso/low.c
@@ -0,0 +1,529 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)low.c 1.4 04/06/17 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <strdefs.h>
+#include <stdxlib.h>
+#include <errno.h>
+#include <unixstd.h>
+#include <fctldefs.h>
+
+#include "internal.h"
+#include "data.h"
+#include "block.h"
+#include "low.h"
+#include "file.h"
+
+/*
+ * NAME: low->lockvol()
+ * DESCRIPTION: prevent destructive simultaneous access
+ */
+int l_lockvol(hfsvol *vol)
+{
+# ifndef NODEVLOCKS
+
+ struct flock lock;
+
+ lock.l_type = (vol->flags & HFS_READONLY) ? F_RDLCK : F_WRLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ if (fcntl(vol->fd, F_SETLK, &lock) < 0)
+ {
+ ERROR(errno, "unable to obtain lock for device");
+ return -1;
+ }
+
+# endif
+
+ return 0;
+}
+
+/*
+ * NAME: low->readblock0()
+ * DESCRIPTION: read the first sector and get bearings
+ */
+int l_readblock0(hfsvol *vol)
+{
+ block b;
+ unsigned char *ptr = b;
+ Block0 rec;
+
+ if (b_readlb(vol, 0, &b) < 0)
+ return -1;
+
+ d_fetchw(&ptr, &rec.sbSig);
+ d_fetchw(&ptr, &rec.sbBlkSize);
+ d_fetchl(&ptr, &rec.sbBlkCount);
+ d_fetchw(&ptr, &rec.sbDevType);
+ d_fetchw(&ptr, &rec.sbDevId);
+ d_fetchl(&ptr, &rec.sbData);
+ d_fetchw(&ptr, &rec.sbDrvrCount);
+ d_fetchl(&ptr, &rec.ddBlock);
+ d_fetchw(&ptr, &rec.ddSize);
+ d_fetchw(&ptr, &rec.ddType);
+
+ switch (rec.sbSig)
+ {
+ case 0x4552: /* block device with a partition table */
+ {
+ if (rec.sbBlkSize != HFS_BLOCKSZ)
+ {
+ ERROR(EINVAL, "unsupported block size");
+ return -1;
+ }
+
+ vol->vlen = rec.sbBlkCount;
+
+ if (l_readpm(vol) < 0)
+ return -1;
+ }
+ break;
+
+ case 0x4c4b: /* bootable floppy */
+ vol->pnum = 0;
+ break;
+
+ default: /* non-bootable floppy or something else */
+
+ /* some miscreant media may also be partitioned;
+ we attempt to read a partition map, but ignore any failure */
+
+ if (l_readpm(vol) < 0)
+ vol->pnum = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: low->readpm()
+ * DESCRIPTION: read the partition map and locate an HFS volume
+ */
+int l_readpm(hfsvol *vol)
+{
+ block b;
+ unsigned char *ptr;
+ Partition map;
+ unsigned long bnum;
+ int pnum;
+
+ bnum = 1;
+ pnum = vol->pnum;
+
+ for (;;)
+ {
+ if (b_readlb(vol, bnum, &b) < 0)
+ return -1;
+
+ ptr = b;
+
+ d_fetchw(&ptr, &map.pmSig);
+ d_fetchw(&ptr, &map.pmSigPad);
+ d_fetchl(&ptr, &map.pmMapBlkCnt);
+ d_fetchl(&ptr, &map.pmPyPartStart);
+ d_fetchl(&ptr, &map.pmPartBlkCnt);
+
+ memcpy(map.pmPartName, ptr, 32);
+ map.pmPartName[32] = 0;
+ ptr += 32;
+
+ memcpy(map.pmParType, ptr, 32);
+ map.pmParType[32] = 0;
+ ptr += 32;
+
+ d_fetchl(&ptr, &map.pmLgDataStart);
+ d_fetchl(&ptr, &map.pmDataCnt);
+ d_fetchl(&ptr, &map.pmPartStatus);
+ d_fetchl(&ptr, &map.pmLgBootStart);
+ d_fetchl(&ptr, &map.pmBootSize);
+ d_fetchl(&ptr, &map.pmBootAddr);
+ d_fetchl(&ptr, &map.pmBootAddr2);
+ d_fetchl(&ptr, &map.pmBootEntry);
+ d_fetchl(&ptr, &map.pmBootEntry2);
+ d_fetchl(&ptr, &map.pmBootCksum);
+
+ memcpy(map.pmProcessor, ptr, 16);
+ map.pmProcessor[16] = 0;
+ ptr += 16;
+
+ if (map.pmSig == 0x5453)
+ {
+ /* old partition map sig */
+
+ ERROR(EINVAL, "unsupported partition map signature");
+ return -1;
+ }
+
+ if (map.pmSig != 0x504d)
+ {
+ ERROR(EINVAL, "bad partition map");
+ return -1;
+ }
+
+ if (strcmp((char *) map.pmParType, "Apple_HFS") == 0 && --pnum == 0)
+ {
+ if (map.pmLgDataStart != 0)
+ {
+ ERROR(EINVAL, "unsupported start of partition logical data");
+ return -1;
+ }
+
+ vol->vstart = map.pmPyPartStart;
+ vol->vlen = map.pmPartBlkCnt;
+
+ return 0;
+ }
+
+ if (bnum >= map.pmMapBlkCnt)
+ {
+ ERROR(EINVAL, "can't find HFS partition");
+ return -1;
+ }
+
+ ++bnum;
+ }
+}
+
+/*
+ * NAME: low->readmdb()
+ * DESCRIPTION: read the master directory block into memory
+ */
+int l_readmdb(hfsvol *vol)
+{
+ block b;
+ unsigned char *ptr = b;
+ MDB *mdb = &vol->mdb;
+ hfsfile *ext = &vol->ext.f;
+ hfsfile *cat = &vol->cat.f;
+ int i;
+
+ if (b_readlb(vol, 2, &b) < 0)
+ return -1;
+
+ d_fetchw(&ptr, &mdb->drSigWord);
+ d_fetchl(&ptr, &mdb->drCrDate);
+ d_fetchl(&ptr, &mdb->drLsMod);
+ d_fetchw(&ptr, &mdb->drAtrb);
+ d_fetchw(&ptr, (short *) &mdb->drNmFls);
+ d_fetchw(&ptr, (short *) &mdb->drVBMSt);
+ d_fetchw(&ptr, (short *) &mdb->drAllocPtr);
+ d_fetchw(&ptr, (short *) &mdb->drNmAlBlks);
+ d_fetchl(&ptr, (long *) &mdb->drAlBlkSiz);
+ d_fetchl(&ptr, (long *) &mdb->drClpSiz);
+ d_fetchw(&ptr, (short *) &mdb->drAlBlSt);
+ d_fetchl(&ptr, &mdb->drNxtCNID);
+ d_fetchw(&ptr, (short *) &mdb->drFreeBks);
+
+ d_fetchs(&ptr, mdb->drVN, sizeof(mdb->drVN));
+
+ if (ptr - b != 64)
+ abort();
+
+ d_fetchl(&ptr, &mdb->drVolBkUp);
+ d_fetchw(&ptr, &mdb->drVSeqNum);
+ d_fetchl(&ptr, (long *) &mdb->drWrCnt);
+ d_fetchl(&ptr, (long *) &mdb->drXTClpSiz);
+ d_fetchl(&ptr, (long *) &mdb->drCTClpSiz);
+ d_fetchw(&ptr, (short *) &mdb->drNmRtDirs);
+ d_fetchl(&ptr, (long *) &mdb->drFilCnt);
+ d_fetchl(&ptr, (long *) &mdb->drDirCnt);
+
+ for (i = 0; i < 8; ++i)
+ d_fetchl(&ptr, &mdb->drFndrInfo[i]);
+
+ if (ptr - b != 124)
+ abort();
+
+ d_fetchw(&ptr, (short *) &mdb->drVCSize);
+ d_fetchw(&ptr, (short *) &mdb->drVBMCSize);
+ d_fetchw(&ptr, (short *) &mdb->drCtlCSize);
+
+ d_fetchl(&ptr, (long *) &mdb->drXTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrStABN);
+ d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrNumABlks);
+ }
+
+ if (ptr - b != 146)
+ abort();
+
+ d_fetchl(&ptr, (long *) &mdb->drCTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrStABN);
+ d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrNumABlks);
+ }
+
+ if (ptr - b != 162)
+ abort();
+
+ vol->lpa = mdb->drAlBlkSiz / HFS_BLOCKSZ;
+
+ /* extents pseudo-file structs */
+
+ ext->vol = vol;
+ ext->parid = 0;
+ strcpy(ext->name, "extents overflow");
+
+ ext->cat.cdrType = cdrFilRec;
+ /* ext->cat.cdrResrv2 */
+ ext->cat.u.fil.filFlags = 0;
+ ext->cat.u.fil.filTyp = 0;
+ /* ext->cat.u.fil.filUsrWds */
+ ext->cat.u.fil.filFlNum = HFS_CNID_EXT;
+ ext->cat.u.fil.filStBlk = mdb->drXTExtRec[0].xdrStABN;
+ ext->cat.u.fil.filLgLen = mdb->drXTFlSize;
+ ext->cat.u.fil.filPyLen = mdb->drXTFlSize;
+ ext->cat.u.fil.filRStBlk = 0;
+ ext->cat.u.fil.filRLgLen = 0;
+ ext->cat.u.fil.filRPyLen = 0;
+ ext->cat.u.fil.filCrDat = mdb->drCrDate;
+ ext->cat.u.fil.filMdDat = mdb->drLsMod;
+ ext->cat.u.fil.filBkDat = 0;
+ /* ext->cat.u.fil.filFndrInfo */
+ ext->cat.u.fil.filClpSize = 0;
+
+ memcpy(ext->cat.u.fil.filExtRec, mdb->drXTExtRec, sizeof(ExtDataRec));
+ for (i = 0; i < 3; ++i)
+ {
+ ext->cat.u.fil.filRExtRec[i].xdrStABN = 0;
+ ext->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+ f_selectfork(ext, 0);
+
+ ext->clump = mdb->drXTClpSiz;
+ ext->flags = 0;
+
+ ext->prev = ext->next = 0;
+
+ /* catalog pseudo-file structs */
+
+ cat->vol = vol;
+ cat->parid = 0;
+ strcpy(cat->name, "catalog");
+
+ cat->cat.cdrType = cdrFilRec;
+ /* cat->cat.cdrResrv2 */
+ cat->cat.u.fil.filFlags = 0;
+ cat->cat.u.fil.filTyp = 0;
+ /* cat->cat.u.fil.filUsrWds */
+ cat->cat.u.fil.filFlNum = HFS_CNID_CAT;
+ cat->cat.u.fil.filStBlk = mdb->drCTExtRec[0].xdrStABN;
+ cat->cat.u.fil.filLgLen = mdb->drCTFlSize;
+ cat->cat.u.fil.filPyLen = mdb->drCTFlSize;
+ cat->cat.u.fil.filRStBlk = 0;
+ cat->cat.u.fil.filRLgLen = 0;
+ cat->cat.u.fil.filRPyLen = 0;
+ cat->cat.u.fil.filCrDat = mdb->drCrDate;
+ cat->cat.u.fil.filMdDat = mdb->drLsMod;
+ cat->cat.u.fil.filBkDat = 0;
+ /* cat->cat.u.fil.filFndrInfo */
+ cat->cat.u.fil.filClpSize = 0;
+
+ memcpy(cat->cat.u.fil.filExtRec, mdb->drCTExtRec, sizeof(ExtDataRec));
+ for (i = 0; i < 3; ++i)
+ {
+ cat->cat.u.fil.filRExtRec[i].xdrStABN = 0;
+ cat->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
+ }
+ f_selectfork(cat, 0);
+
+ cat->clump = mdb->drCTClpSiz;
+ cat->flags = 0;
+
+ cat->prev = cat->next = 0;
+
+ return 0;
+}
+
+/*
+ * NAME: low->writemdb()
+ * DESCRIPTION: write the master directory block to disk
+ */
+int l_writemdb(hfsvol *vol)
+{
+ block b;
+ unsigned char *ptr = b;
+ MDB *mdb = &vol->mdb;
+ hfsfile *ext = &vol->ext.f;
+ hfsfile *cat = &vol->cat.f;
+ int i;
+
+ memset(&b, 0, sizeof(b));
+
+ mdb->drXTFlSize = ext->cat.u.fil.filPyLen;
+ mdb->drXTClpSiz = ext->clump;
+ memcpy(mdb->drXTExtRec, ext->cat.u.fil.filExtRec, sizeof(ExtDataRec));
+
+ mdb->drCTFlSize = cat->cat.u.fil.filPyLen;
+ mdb->drCTClpSiz = cat->clump;
+ memcpy(mdb->drCTExtRec, cat->cat.u.fil.filExtRec, sizeof(ExtDataRec));
+
+ d_storew(&ptr, mdb->drSigWord);
+ d_storel(&ptr, mdb->drCrDate);
+ d_storel(&ptr, mdb->drLsMod);
+ d_storew(&ptr, mdb->drAtrb);
+ d_storew(&ptr, mdb->drNmFls);
+ d_storew(&ptr, mdb->drVBMSt);
+ d_storew(&ptr, mdb->drAllocPtr);
+ d_storew(&ptr, mdb->drNmAlBlks);
+ d_storel(&ptr, mdb->drAlBlkSiz);
+ d_storel(&ptr, mdb->drClpSiz);
+ d_storew(&ptr, mdb->drAlBlSt);
+ d_storel(&ptr, mdb->drNxtCNID);
+ d_storew(&ptr, mdb->drFreeBks);
+ d_stores(&ptr, mdb->drVN, sizeof(mdb->drVN));
+
+ if (ptr - b != 64)
+ abort();
+
+ d_storel(&ptr, mdb->drVolBkUp);
+ d_storew(&ptr, mdb->drVSeqNum);
+ d_storel(&ptr, mdb->drWrCnt);
+ d_storel(&ptr, mdb->drXTClpSiz);
+ d_storel(&ptr, mdb->drCTClpSiz);
+ d_storew(&ptr, mdb->drNmRtDirs);
+ d_storel(&ptr, mdb->drFilCnt);
+ d_storel(&ptr, mdb->drDirCnt);
+
+ for (i = 0; i < 8; ++i)
+ d_storel(&ptr, mdb->drFndrInfo[i]);
+
+ if (ptr - b != 124)
+ abort();
+
+ d_storew(&ptr, mdb->drVCSize);
+ d_storew(&ptr, mdb->drVBMCSize);
+ d_storew(&ptr, mdb->drCtlCSize);
+ d_storel(&ptr, mdb->drXTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storew(&ptr, mdb->drXTExtRec[i].xdrStABN);
+ d_storew(&ptr, mdb->drXTExtRec[i].xdrNumABlks);
+ }
+
+ if (ptr - b != 146)
+ abort();
+
+ d_storel(&ptr, mdb->drCTFlSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storew(&ptr, mdb->drCTExtRec[i].xdrStABN);
+ d_storew(&ptr, mdb->drCTExtRec[i].xdrNumABlks);
+ }
+
+ if (ptr - b != 162)
+ abort();
+
+ if (b_writelb(vol, 2, &b) < 0)
+ return -1;
+ if (vol->flags & HFS_UPDATE_ALTMDB)
+ {
+#ifdef APPLE_HYB
+ /* "write" alternative MDB to memory copy */
+ memcpy(vol->hce->hfs_alt_mdb, &b, sizeof(b));
+#else
+ if (b_writelb(vol, vol->vlen - 2, &b) < 0)
+ return -1;
+#endif /* APPLE_HYB */
+ }
+ vol->flags &= ~(HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB);
+
+ return 0;
+}
+
+/*
+ * NAME: low->readvbm()
+ * DESCRIPTION: read the volume bit map into memory
+ */
+int l_readvbm(hfsvol *vol)
+{
+ int vbmst = vol->mdb.drVBMSt;
+ int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
+ block *bp;
+
+ if ((int)(vol->mdb.drAlBlSt - vbmst) < vbmsz)
+ {
+ ERROR(EIO, "volume bitmap collides with volume data");
+ return -1;
+ }
+
+ bp = ALLOC(block, vbmsz);
+ if (bp == 0)
+ {
+ ERROR(ENOMEM, 0);
+ return -1;
+ }
+
+ vol->vbm = bp;
+
+ while (vbmsz--)
+ {
+ if (b_readlb(vol, vbmst++, bp++) < 0)
+ {
+ FREE(vol->vbm);
+ vol->vbm = 0;
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: low->writevbm()
+ * DESCRIPTION: write the volume bit map to disk
+ */
+int l_writevbm(hfsvol *vol)
+{
+ int vbmst = vol->mdb.drVBMSt;
+ int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
+ block *bp = vol->vbm;
+
+ while (vbmsz--)
+ {
+ if (b_writelb(vol, vbmst++, bp++) < 0)
+ return -1;
+ }
+
+ vol->flags &= ~HFS_UPDATE_VBM;
+
+ return 0;
+}
diff --git a/libhfs_iso/low.h b/libhfs_iso/low.h
new file mode 100644
index 0000000..4434444
--- /dev/null
+++ b/libhfs_iso/low.h
@@ -0,0 +1,111 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)low.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+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 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 {
+ 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 */
+ /*
+ * 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
+ */
+ 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;
+
+int l_lockvol(hfsvol *);
+
+int l_readblock0(hfsvol *);
+int l_readpm(hfsvol *);
+
+int l_readmdb(hfsvol *);
+int l_writemdb(hfsvol *);
+
+int l_readvbm(hfsvol *);
+int l_writevbm(hfsvol *);
diff --git a/libhfs_iso/node.c b/libhfs_iso/node.c
new file mode 100644
index 0000000..8fce735
--- /dev/null
+++ b/libhfs_iso/node.c
@@ -0,0 +1,473 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)node.c 1.2 02/02/10 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <strdefs.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "btree.h"
+#include "node.h"
+
+# define NODESPACE(n) \
+ (HFS_BLOCKSZ - (n).roff[(n).nd.ndNRecs] - 2 * ((n).nd.ndNRecs + 1))
+
+/*
+ * NAME: node->init()
+ * DESCRIPTION: construct an empty node
+ */
+void n_init(node *np, btree *bt, int type, int height)
+{
+ np->bt = bt;
+ np->nnum = -1;
+
+ np->nd.ndFLink = 0;
+ np->nd.ndBLink = 0;
+ np->nd.ndType = type;
+ np->nd.ndNHeight = height;
+ np->nd.ndNRecs = 0;
+ np->nd.ndResv2 = 0;
+
+ np->rnum = -1;
+ np->roff[0] = 0x00e;
+
+ memset(np->data, 0, sizeof(np->data));
+}
+
+/*
+ * NAME: node->new()
+ * DESCRIPTION: allocate a new b*-tree node
+ */
+int n_new(node *np)
+{
+ btree *bt = np->bt;
+ unsigned long num;
+
+ if (bt->hdr.bthFree == 0)
+ {
+ ERROR(EIO, "b*-tree full");
+ return -1;
+ }
+
+ num = 0;
+ while (num < bt->hdr.bthNNodes && BMTST(bt->map, num))
+ ++num;
+
+ if (num == bt->hdr.bthNNodes)
+ {
+ ERROR(EIO, "free b*-tree node not found");
+ return -1;
+ }
+
+ np->nnum = num;
+
+ BMSET(bt->map, num);
+ --bt->hdr.bthFree;
+
+ bt->flags |= HFS_UPDATE_BTHDR;
+
+ return 0;
+}
+
+/*
+ * NAME: node->free()
+ * DESCRIPTION: deallocate a b*-tree node
+ */
+void n_free(node *np)
+{
+ btree *bt = np->bt;
+
+ BMCLR(bt->map, np->nnum);
+ ++bt->hdr.bthFree;
+
+ bt->flags |= HFS_UPDATE_BTHDR;
+}
+
+/*
+ * NAME: node->compact()
+ * DESCRIPTION: clean up a node, removing deleted records
+ */
+void n_compact(node *np)
+{
+ unsigned char *ptr;
+ int offset, nrecs, i;
+
+ offset = 0x00e;
+ ptr = np->data + offset;
+ nrecs = 0;
+
+ for (i = 0; i < (int)np->nd.ndNRecs; ++i)
+ {
+ unsigned char *rec;
+ int reclen;
+
+ rec = HFS_NODEREC(*np, i);
+ reclen = np->roff[i + 1] - np->roff[i];
+
+ if (HFS_RECKEYLEN(rec) > 0)
+ {
+ np->roff[nrecs++] = offset;
+ offset += reclen;
+
+ if (ptr == rec)
+ ptr += reclen;
+ else
+ {
+ while (reclen--)
+ *ptr++ = *rec++;
+ }
+ }
+ }
+
+ np->roff[nrecs] = offset;
+ np->nd.ndNRecs = nrecs;
+}
+
+/*
+ * NAME: node->search()
+ * DESCRIPTION: locate a record in a node, or the record it should follow
+ */
+int n_search(node *np, unsigned char *key)
+{
+ btree *bt = np->bt;
+ int i, comp = -1;
+
+ for (i = np->nd.ndNRecs; i--; )
+ {
+ unsigned char *rec;
+
+ rec = HFS_NODEREC(*np, i);
+
+ if (HFS_RECKEYLEN(rec) == 0)
+ continue; /* deleted record */
+
+ comp = bt->compare(rec, key);
+
+ if (comp <= 0)
+ break;
+ }
+
+ np->rnum = i;
+
+ return comp == 0;
+}
+
+/*
+ * NAME: node->index()
+ * DESCRIPTION: create an index record from a key and node pointer
+ */
+void n_index(btree *bt, unsigned char *key, unsigned long nnum,
+ unsigned char *record, int *reclen)
+{
+ if (bt == &bt->f.vol->cat)
+ {
+ /* force the key length to be 0x25 */
+
+ HFS_RECKEYLEN(record) = 0x25;
+ memset(record + 1, 0, 0x25);
+ memcpy(record + 1, key + 1, HFS_RECKEYLEN(key));
+ }
+ else
+ memcpy(record, key, HFS_RECKEYSKIP(key));
+
+ d_putl(HFS_RECDATA(record), nnum);
+
+ if (reclen)
+ *reclen = HFS_RECKEYSKIP(record) + 4;
+}
+
+/*
+ * NAME: node->split()
+ * DESCRIPTION: divide a node into two and insert a record
+ */
+int n_split(node *left, unsigned char *record, int *reclen)
+{
+ node right;
+ int nrecs, i, mid;
+ unsigned char *rec;
+
+ right = *left;
+ right.nd.ndBLink = left->nnum;
+
+ if (n_new(&right) < 0)
+ return -1;
+
+ left->nd.ndFLink = right.nnum;
+ nrecs = left->nd.ndNRecs;
+
+ /*
+ * Ensure node split leaves enough room for new record.
+ * The size calculations used are based on the NODESPACE() macro, but
+ * I don't know what the extra 2's and 1's are needed for.
+ * John Witford <jwitford@hutch.com.au>
+ */
+ n_search(&right, record);
+ mid = nrecs/2;
+ for(;;)
+ {
+ if (right.rnum < mid)
+ {
+ if ( mid > 0
+ && (int)left->roff[mid] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
+ {
+ --mid;
+ if (mid > 0)
+ continue;
+ }
+ }
+ else
+ {
+ if ( mid < nrecs
+ && (int)right.roff[nrecs] - (int)right.roff[mid] + (int)left->roff[0] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
+ {
+ ++mid;
+ if (mid < nrecs)
+ continue;
+ }
+ }
+ break;
+ }
+
+ for (i = 0; i < nrecs; ++i)
+ {
+ if (i < mid)
+ rec = HFS_NODEREC(right, i);
+ else
+ rec = HFS_NODEREC(*left, i);
+
+ HFS_RECKEYLEN(rec) = 0;
+ }
+
+/* original code ...
+ for (i = 0; i < nrecs; ++i)
+ {
+ if (i < nrecs / 2)
+ rec = HFS_NODEREC(right, i);
+ else
+ rec = HFS_NODEREC(*left, i);
+
+ HFS_RECKEYLEN(rec) = 0;
+ }
+*/
+ n_compact(left);
+ n_compact(&right);
+
+ n_search(&right, record);
+ if (right.rnum >= 0)
+ n_insertx(&right, record, *reclen);
+ else
+ {
+ n_search(left, record);
+ n_insertx(left, record, *reclen);
+ }
+
+ /* store the new/modified nodes */
+
+ if (bt_putnode(left) < 0 ||
+ bt_putnode(&right) < 0)
+ return -1;
+
+ /* create an index record for the new node in the parent */
+
+ n_index(right.bt, HFS_NODEREC(right, 0), right.nnum, record, reclen);
+
+ /* update link pointers */
+
+ if (left->bt->hdr.bthLNode == left->nnum)
+ {
+ left->bt->hdr.bthLNode = right.nnum;
+ left->bt->flags |= HFS_UPDATE_BTHDR;
+ }
+
+ if (right.nd.ndFLink)
+ {
+ node n;
+
+ n.bt = right.bt;
+ n.nnum = right.nd.ndFLink;
+
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.nd.ndBLink = right.nnum;
+
+ if (bt_putnode(&n) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: node->insertx()
+ * DESCRIPTION: insert a record into a node (which must already have room)
+ */
+void n_insertx(node *np, unsigned char *record, int reclen)
+{
+ int rnum, i;
+ unsigned char *ptr;
+
+ rnum = np->rnum + 1;
+
+ /* push other records down to make room */
+
+ for (ptr = HFS_NODEREC(*np, np->nd.ndNRecs) + reclen;
+ ptr > HFS_NODEREC(*np, rnum) + reclen; --ptr)
+ *(ptr - 1) = *(ptr - 1 - reclen);
+
+ ++np->nd.ndNRecs;
+
+ for (i = np->nd.ndNRecs; i > rnum; --i)
+ np->roff[i] = np->roff[i - 1] + reclen;
+
+ /* write the new record */
+
+ memcpy(HFS_NODEREC(*np, rnum), record, reclen);
+}
+
+/*
+ * NAME: node->insert()
+ * DESCRIPTION: insert a new record into a node; return a record for parent
+ */
+int n_insert(node *np, unsigned char *record, int *reclen)
+{
+ n_compact(np);
+
+ /* check for free space */
+
+ if (np->nd.ndNRecs >= HFS_MAXRECS ||
+ *reclen + 2 > (int)NODESPACE(*np))
+ return n_split(np, record, reclen);
+
+ n_insertx(np, record, *reclen);
+ *reclen = 0;
+
+ return bt_putnode(np);
+}
+
+/*
+ * NAME: node->merge()
+ * DESCRIPTION: combine two nodes into a single node
+ */
+int n_merge(node *right, node *left, unsigned char *record, int *flag)
+{
+ int i, offset;
+
+ /* copy records and offsets */
+
+ memcpy(HFS_NODEREC(*left, left->nd.ndNRecs), HFS_NODEREC(*right, 0),
+ right->roff[right->nd.ndNRecs] - right->roff[0]);
+
+ offset = left->roff[left->nd.ndNRecs] - right->roff[0];
+
+ for (i = 1; i <= (int)right->nd.ndNRecs; ++i)
+ left->roff[++left->nd.ndNRecs] = offset + right->roff[i];
+
+ /* update link pointers */
+
+ left->nd.ndFLink = right->nd.ndFLink;
+
+ if (bt_putnode(left) < 0)
+ return -1;
+
+ if (right->bt->hdr.bthLNode == right->nnum)
+ {
+ right->bt->hdr.bthLNode = left->nnum;
+ right->bt->flags |= HFS_UPDATE_BTHDR;
+ }
+
+ if (right->nd.ndFLink)
+ {
+ node n;
+
+ n.bt = right->bt;
+ n.nnum = right->nd.ndFLink;
+
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.nd.ndBLink = left->nnum;
+
+ if (bt_putnode(&n) < 0)
+ return -1;
+ }
+
+ n_free(right);
+
+ HFS_RECKEYLEN(record) = 0;
+ *flag = 1;
+
+ return 0;
+}
+
+/*
+ * NAME: node->delete()
+ * DESCRIPTION: remove a record from a node
+ */
+int n_delete(node *np, unsigned char *record, int *flag)
+{
+ node left;
+ unsigned char *rec;
+
+ rec = HFS_NODEREC(*np, np->rnum);
+
+ HFS_RECKEYLEN(rec) = 0;
+ n_compact(np);
+
+ /* see if we can merge with our left sibling */
+
+ left.bt = np->bt;
+ left.nnum = np->nd.ndBLink;
+
+ if (left.nnum > 0)
+ {
+ if (bt_getnode(&left) < 0)
+ return -1;
+
+ if ((int)(np->nd.ndNRecs + left.nd.ndNRecs) <= HFS_MAXRECS &&
+ (int)(np->roff[np->nd.ndNRecs] - np->roff[0] +
+ 2 * np->nd.ndNRecs) <= (int)NODESPACE(left))
+ return n_merge(np, &left, record, flag);
+ }
+
+ if (np->rnum == 0)
+ {
+ /* special case: first record changed; update parent record key */
+
+ n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);
+ *flag = 1;
+ }
+
+ return bt_putnode(np);
+}
diff --git a/libhfs_iso/node.h b/libhfs_iso/node.h
new file mode 100644
index 0000000..39d3227
--- /dev/null
+++ b/libhfs_iso/node.h
@@ -0,0 +1,48 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)node.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+void n_init(node *, btree *, int, int);
+
+int n_new(node *);
+void n_free(node *);
+
+void n_compact(node *);
+int n_search(node *, unsigned char *);
+
+void n_index(btree *, unsigned char *, unsigned long, unsigned char *, int *);
+int n_split(node *, unsigned char *, int *);
+
+void n_insertx(node *, unsigned char *, int);
+int n_insert(node *, unsigned char *, int *);
+
+int n_merge(node *, node *, unsigned char *, int *);
+int n_delete(node *, unsigned char *, int *);
diff --git a/libhfs_iso/record.c b/libhfs_iso/record.c
new file mode 100644
index 0000000..e202158
--- /dev/null
+++ b/libhfs_iso/record.c
@@ -0,0 +1,551 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)record.c 1.1 00/04/26 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <strdefs.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "record.h"
+
+/*
+ * NAME: record->packcatkey()
+ * DESCRIPTION: pack a catalog record key
+ */
+void r_packcatkey(CatKeyRec *key, unsigned char *pkey, int *len)
+{
+ unsigned char *start = pkey;
+
+ d_storeb(&pkey, key->ckrKeyLen);
+ d_storeb(&pkey, key->ckrResrv1);
+ d_storel(&pkey, key->ckrParID);
+ d_stores(&pkey, key->ckrCName, sizeof(key->ckrCName));
+
+ if (len)
+ *len = HFS_RECKEYSKIP(start);
+}
+
+/*
+ * NAME: record->unpackcatkey()
+ * DESCRIPTION: unpack a catalog record key
+ */
+void r_unpackcatkey(unsigned char *pkey, CatKeyRec *key)
+{
+ d_fetchb(&pkey, (char *) &key->ckrKeyLen);
+ d_fetchb(&pkey, (char *) &key->ckrResrv1);
+ d_fetchl(&pkey, (long *) &key->ckrParID);
+ d_fetchs(&pkey, key->ckrCName, sizeof(key->ckrCName));
+}
+
+/*
+ * NAME: record->packextkey()
+ * DESCRIPTION: pack an extents record key
+ */
+void r_packextkey(ExtKeyRec *key, unsigned char *pkey, int *len)
+{
+ unsigned char *start = pkey;
+
+ d_storeb(&pkey, key->xkrKeyLen);
+ d_storeb(&pkey, key->xkrFkType);
+ d_storel(&pkey, key->xkrFNum);
+ d_storew(&pkey, key->xkrFABN);
+
+ if (len)
+ *len = HFS_RECKEYSKIP(start);
+}
+
+/*
+ * NAME: record->unpackextkey()
+ * DESCRIPTION: unpack an extents record key
+ */
+void r_unpackextkey(unsigned char *pkey, ExtKeyRec *key)
+{
+ d_fetchb(&pkey, (char *) &key->xkrKeyLen);
+ d_fetchb(&pkey, (char *) &key->xkrFkType);
+ d_fetchl(&pkey, (long *) &key->xkrFNum);
+ d_fetchw(&pkey, (short *) &key->xkrFABN);
+}
+
+/*
+ * NAME: record->comparecatkeys()
+ * DESCRIPTION: compare two (packed) catalog record keys
+ */
+int r_comparecatkeys(unsigned char *pkey1, unsigned char *pkey2)
+{
+ CatKeyRec key1;
+ CatKeyRec key2;
+ int diff;
+
+ r_unpackcatkey(pkey1, &key1);
+ r_unpackcatkey(pkey2, &key2);
+
+ 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(unsigned char *pkey1, unsigned char *pkey2)
+{
+ ExtKeyRec key1;
+ ExtKeyRec key2;
+ int diff;
+
+ r_unpackextkey(pkey1, &key1);
+ r_unpackextkey(pkey2, &key2);
+
+ 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(CatDataRec *data, unsigned char *pdata, int *len)
+{
+ unsigned char *start = pdata;
+ int i;
+
+ d_storeb(&pdata, data->cdrType);
+ d_storeb(&pdata, data->cdrResrv2);
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ d_storew(&pdata, data->u.dir.dirFlags);
+ d_storew(&pdata, data->u.dir.dirVal);
+ d_storel(&pdata, data->u.dir.dirDirID);
+ d_storel(&pdata, data->u.dir.dirCrDat);
+ d_storel(&pdata, data->u.dir.dirMdDat);
+ d_storel(&pdata, data->u.dir.dirBkDat);
+
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.top);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.left);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.bottom);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.right);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frFlags);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frLocation.v);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frLocation.h);
+ d_storew(&pdata, data->u.dir.dirUsrInfo.frView);
+
+ d_storew(&pdata, data->u.dir.dirFndrInfo.frScroll.v);
+ d_storew(&pdata, data->u.dir.dirFndrInfo.frScroll.h);
+ d_storel(&pdata, data->u.dir.dirFndrInfo.frOpenChain);
+ d_storew(&pdata, data->u.dir.dirFndrInfo.frUnused);
+ d_storew(&pdata, data->u.dir.dirFndrInfo.frComment);
+ d_storel(&pdata, data->u.dir.dirFndrInfo.frPutAway);
+
+ for (i = 0; i < 4; ++i)
+ d_storel(&pdata, data->u.dir.dirResrv[i]);
+
+ break;
+
+ case cdrFilRec:
+ d_storeb(&pdata, data->u.fil.filFlags);
+ d_storeb(&pdata, data->u.fil.filTyp);
+
+ d_storel(&pdata, data->u.fil.filUsrWds.fdType);
+ d_storel(&pdata, data->u.fil.filUsrWds.fdCreator);
+ d_storew(&pdata, data->u.fil.filUsrWds.fdFlags);
+ d_storew(&pdata, data->u.fil.filUsrWds.fdLocation.v);
+ d_storew(&pdata, data->u.fil.filUsrWds.fdLocation.h);
+ d_storew(&pdata, data->u.fil.filUsrWds.fdFldr);
+
+ d_storel(&pdata, data->u.fil.filFlNum);
+
+ d_storew(&pdata, data->u.fil.filStBlk);
+ d_storel(&pdata, data->u.fil.filLgLen);
+ d_storel(&pdata, data->u.fil.filPyLen);
+
+ d_storew(&pdata, data->u.fil.filRStBlk);
+ d_storel(&pdata, data->u.fil.filRLgLen);
+ d_storel(&pdata, data->u.fil.filRPyLen);
+
+ d_storel(&pdata, data->u.fil.filCrDat);
+ d_storel(&pdata, data->u.fil.filMdDat);
+ d_storel(&pdata, data->u.fil.filBkDat);
+
+ d_storew(&pdata, data->u.fil.filFndrInfo.fdIconID);
+ for (i = 0; i < 4; ++i)
+ d_storew(&pdata, data->u.fil.filFndrInfo.fdUnused[i]);
+ d_storew(&pdata, data->u.fil.filFndrInfo.fdComment);
+ d_storel(&pdata, data->u.fil.filFndrInfo.fdPutAway);
+
+ d_storew(&pdata, data->u.fil.filClpSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storew(&pdata, data->u.fil.filExtRec[i].xdrStABN);
+ d_storew(&pdata, data->u.fil.filExtRec[i].xdrNumABlks);
+ }
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storew(&pdata, data->u.fil.filRExtRec[i].xdrStABN);
+ d_storew(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks);
+ }
+
+ d_storel(&pdata, data->u.fil.filResrv);
+ break;
+
+ case cdrThdRec:
+ for (i = 0; i < 2; ++i)
+ d_storel(&pdata, data->u.dthd.thdResrv[i]);
+
+ d_storel(&pdata, data->u.dthd.thdParID);
+ d_stores(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName));
+ break;
+
+ case cdrFThdRec:
+ for (i = 0; i < 2; ++i)
+ d_storel(&pdata, data->u.fthd.fthdResrv[i]);
+
+ d_storel(&pdata, data->u.fthd.fthdParID);
+ d_stores(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName));
+ break;
+
+ default:
+ abort();
+ }
+
+ if (len)
+ *len += pdata - start;
+}
+
+/*
+ * NAME: record->unpackcatdata()
+ * DESCRIPTION: unpack catalog record data
+ */
+void r_unpackcatdata(unsigned char *pdata, CatDataRec *data)
+{
+ int i;
+
+ d_fetchb(&pdata, (char *) &data->cdrType);
+ d_fetchb(&pdata, (char *) &data->cdrResrv2);
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ d_fetchw(&pdata, &data->u.dir.dirFlags);
+ d_fetchw(&pdata, (short *) &data->u.dir.dirVal);
+ d_fetchl(&pdata, (long *) &data->u.dir.dirDirID);
+ d_fetchl(&pdata, &data->u.dir.dirCrDat);
+ d_fetchl(&pdata, &data->u.dir.dirMdDat);
+ d_fetchl(&pdata, &data->u.dir.dirBkDat);
+
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.top);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.left);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.right);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frFlags);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h);
+ d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frView);
+
+ d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v);
+ d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h);
+ d_fetchl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain);
+ d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frUnused);
+ d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frComment);
+ d_fetchl(&pdata, &data->u.dir.dirFndrInfo.frPutAway);
+
+ for (i = 0; i < 4; ++i)
+ d_fetchl(&pdata, &data->u.dir.dirResrv[i]);
+
+ break;
+
+ case cdrFilRec:
+ d_fetchb(&pdata, (char *) &data->u.fil.filFlags);
+ d_fetchb(&pdata, (char *) &data->u.fil.filTyp);
+
+ d_fetchl(&pdata, &data->u.fil.filUsrWds.fdType);
+ d_fetchl(&pdata, &data->u.fil.filUsrWds.fdCreator);
+ d_fetchw(&pdata, &data->u.fil.filUsrWds.fdFlags);
+ d_fetchw(&pdata, &data->u.fil.filUsrWds.fdLocation.v);
+ d_fetchw(&pdata, &data->u.fil.filUsrWds.fdLocation.h);
+ d_fetchw(&pdata, &data->u.fil.filUsrWds.fdFldr);
+
+ d_fetchl(&pdata, (long *) &data->u.fil.filFlNum);
+
+ d_fetchw(&pdata, (short *) &data->u.fil.filStBlk);
+ d_fetchl(&pdata, (long *) &data->u.fil.filLgLen);
+ d_fetchl(&pdata, (long *) &data->u.fil.filPyLen);
+
+ d_fetchw(&pdata, (short *) &data->u.fil.filRStBlk);
+ d_fetchl(&pdata, (long *) &data->u.fil.filRLgLen);
+ d_fetchl(&pdata, (long *) &data->u.fil.filRPyLen);
+
+ d_fetchl(&pdata, &data->u.fil.filCrDat);
+ d_fetchl(&pdata, &data->u.fil.filMdDat);
+ d_fetchl(&pdata, &data->u.fil.filBkDat);
+
+ d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdIconID);
+ for (i = 0; i < 4; ++i)
+ d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]);
+ d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdComment);
+ d_fetchl(&pdata, &data->u.fil.filFndrInfo.fdPutAway);
+
+ d_fetchw(&pdata, (short *) &data->u.fil.filClpSize);
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchw(&pdata, (short *) &data->u.fil.filExtRec[i].xdrStABN);
+ d_fetchw(&pdata, (short *) &data->u.fil.filExtRec[i].xdrNumABlks);
+ }
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchw(&pdata, (short *) &data->u.fil.filRExtRec[i].xdrStABN);
+ d_fetchw(&pdata, (short *) &data->u.fil.filRExtRec[i].xdrNumABlks);
+ }
+
+ d_fetchl(&pdata, &data->u.fil.filResrv);
+ break;
+
+ case cdrThdRec:
+ for (i = 0; i < 2; ++i)
+ d_fetchl(&pdata, &data->u.dthd.thdResrv[i]);
+
+ d_fetchl(&pdata, (long *) &data->u.dthd.thdParID);
+ d_fetchs(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName));
+ break;
+
+ case cdrFThdRec:
+ for (i = 0; i < 2; ++i)
+ d_fetchl(&pdata, &data->u.fthd.fthdResrv[i]);
+
+ d_fetchl(&pdata, (long *) &data->u.fthd.fthdParID);
+ d_fetchs(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName));
+ break;
+
+ default:
+ abort();
+ }
+}
+
+/*
+ * NAME: record->packextdata()
+ * DESCRIPTION: pack extent record data
+ */
+void r_packextdata(ExtDataRec *data, unsigned char *pdata, int *len)
+{
+ unsigned char *start = pdata;
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_storew(&pdata, (*data)[i].xdrStABN);
+ d_storew(&pdata, (*data)[i].xdrNumABlks);
+ }
+
+ if (len)
+ *len += pdata - start;
+}
+
+/*
+ * NAME: record->unpackextdata()
+ * DESCRIPTION: unpack extent record data
+ */
+void r_unpackextdata(unsigned char *pdata, ExtDataRec *data)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ d_fetchw(&pdata, (short *) &(*data)[i].xdrStABN);
+ d_fetchw(&pdata, (short *) &(*data)[i].xdrNumABlks);
+ }
+}
+
+/*
+ * NAME: record->makecatkey()
+ * DESCRIPTION: construct a catalog record key
+ */
+void r_makecatkey(CatKeyRec *key, long parid, 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 ffork, long fnum, unsigned int fabn)
+{
+ key->xkrKeyLen = 0x07;
+ key->xkrFkType = ffork;
+ key->xkrFNum = fnum;
+ key->xkrFABN = fabn;
+}
+
+/*
+ * NAME: record->unpackdirent()
+ * DESCRIPTION: unpack catalog information into hfsdirent structure
+ *
+ * Taken fron v3.2.6
+ */
+void r_unpackdirent(long parid, char *name, 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_toutime(data->u.dir.dirCrDat);
+ ent->mddate = d_toutime(data->u.dir.dirMdDat);
+ ent->bkdate = d_toutime(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;
+
+ /* mkhybrid extra */
+ ent->u.dir.frscroll.v = data->u.dir.dirFndrInfo.frScroll.v;
+ ent->u.dir.frscroll.h = data->u.dir.dirFndrInfo.frScroll.h;
+ ent->u.dir.view = data->u.dir.dirUsrInfo.frView;
+
+ break;
+
+ case cdrFilRec:
+ ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0;
+ ent->cnid = data->u.fil.filFlNum;
+
+ ent->crdate = d_toutime(data->u.fil.filCrDat);
+ ent->mddate = d_toutime(data->u.fil.filMdDat);
+ ent->bkdate = d_toutime(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_putl((unsigned char *) ent->u.file.type,
+ data->u.fil.filUsrWds.fdType);
+ d_putl((unsigned char *) ent->u.file.creator,
+ data->u.fil.filUsrWds.fdCreator);
+
+ ent->u.file.type[4] = ent->u.file.creator[4] = 0;
+
+ break;
+ }
+}
+
+/*
+ * NAME: record->packdirent()
+ * DESCRIPTION: make changes to a catalog record
+ *
+ * Taken fron v3.2.6
+ */
+void r_packdirent(CatDataRec *data, hfsdirent *ent)
+{
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ data->u.dir.dirCrDat = d_tomtime(ent->crdate);
+ data->u.dir.dirMdDat = d_tomtime(ent->mddate);
+ data->u.dir.dirBkDat = d_tomtime(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;
+
+ /* mkhybrid extra */
+ data->u.dir.dirFndrInfo.frScroll.v = ent->u.dir.frscroll.v;
+ data->u.dir.dirFndrInfo.frScroll.h = ent->u.dir.frscroll.h;
+ data->u.dir.dirUsrInfo.frView = ent->u.dir.view;
+
+ 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_tomtime(ent->crdate);
+ data->u.fil.filMdDat = d_tomtime(ent->mddate);
+ data->u.fil.filBkDat = d_tomtime(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_getl((unsigned char *) ent->u.file.type);
+ data->u.fil.filUsrWds.fdCreator =
+ d_getl((unsigned char *) ent->u.file.creator);
+
+ break;
+ }
+}
diff --git a/libhfs_iso/record.h b/libhfs_iso/record.h
new file mode 100644
index 0000000..90934eb
--- /dev/null
+++ b/libhfs_iso/record.h
@@ -0,0 +1,52 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)record.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+void r_packcatkey(CatKeyRec *, unsigned char *, int *);
+void r_unpackcatkey(unsigned char *, CatKeyRec *);
+
+void r_packextkey(ExtKeyRec *, unsigned char *, int *);
+void r_unpackextkey(unsigned char *, ExtKeyRec *);
+
+int r_comparecatkeys(unsigned char *, unsigned char *);
+int r_compareextkeys(unsigned char *, unsigned char *);
+
+void r_packcatdata(CatDataRec *, unsigned char *, int *);
+void r_unpackcatdata(unsigned char *, CatDataRec *);
+
+void r_packextdata(ExtDataRec *, unsigned char *, int *);
+void r_unpackextdata(unsigned char *, ExtDataRec *);
+
+void r_makecatkey(CatKeyRec *, long, char *);
+void r_makeextkey(ExtKeyRec *, int, long, unsigned int);
+
+void r_unpackdirent(long, char *, CatDataRec *, hfsdirent *);
+void r_packdirent(CatDataRec *, hfsdirent *);
diff --git a/libhfs_iso/volume.c b/libhfs_iso/volume.c
new file mode 100644
index 0000000..b352735
--- /dev/null
+++ b/libhfs_iso/volume.c
@@ -0,0 +1,741 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)volume.c 1.4 04/06/17 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <strdefs.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "data.h"
+#include "low.h"
+#include "btree.h"
+#include "record.h"
+#include "volume.h"
+
+static void markexts(block *vbm, ExtDataRec *exts);
+
+
+/*
+ * NAME: vol->catsearch()
+ * DESCRIPTION: search catalog tree
+ */
+int v_catsearch(hfsvol *vol, long parid, char *name, CatDataRec *data,
+ char *cname, node *np)
+{
+ CatKeyRec key;
+ unsigned char pkey[HFS_CATKEYLEN];
+ node n;
+ unsigned char *ptr;
+ int found;
+
+ if (np == 0)
+ np = &n;
+
+ r_makecatkey(&key, parid, name);
+ r_packcatkey(&key, pkey, 0);
+
+ 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;
+ unsigned char pkey[HFS_EXTKEYLEN];
+ node n;
+ unsigned char *ptr;
+ int found;
+
+ if (np == 0)
+ np = &n;
+
+ r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn);
+ r_packextkey(&key, pkey, 0);
+
+ /* 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, long id, CatDataRec *thread, node *np, int type)
+{
+ CatDataRec rec;
+ int found;
+
+ if (thread == 0)
+ thread = &rec;
+
+ found = v_catsearch(vol, id, "", thread, 0, np);
+ if (found <= 0)
+ return found;
+
+ if (thread->cdrType != type)
+ {
+ ERROR(EIO, "bad thread record");
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+ * NAME: vol->putcatrec()
+ * DESCRIPTION: store catalog information
+ */
+int v_putcatrec(CatDataRec *data, node *np)
+{
+ unsigned char pdata[HFS_CATDATALEN], *ptr;
+ int len = 0;
+
+ r_packcatdata(data, pdata, &len);
+
+ ptr = HFS_NODEREC(*np, np->rnum);
+ memcpy(HFS_RECDATA(ptr), pdata, len);
+
+ return bt_putnode(np);
+}
+
+/*
+ * NAME: vol->putextrec()
+ * DESCRIPTION: store extent information
+ */
+int v_putextrec(ExtDataRec *data, node *np)
+{
+ unsigned char pdata[HFS_EXTDATALEN], *ptr;
+ int len = 0;
+
+ r_packextdata(data, pdata, &len);
+
+ ptr = HFS_NODEREC(*np, np->rnum);
+ memcpy(HFS_RECDATA(ptr), pdata, len);
+
+ return bt_putnode(np);
+}
+
+/*
+ * NAME: vol->allocblocks()
+ * DESCRIPTION: allocate a contiguous range of blocks
+ */
+int v_allocblocks(hfsvol *vol, ExtDescriptor *blocks)
+{
+ unsigned int request, found, foundat, start, end, pt;
+ block *vbm;
+ int wrap = 0;
+
+ if (vol->mdb.drFreeBks == 0)
+ {
+ ERROR(ENOSPC, "volume full");
+ return -1;
+ }
+
+ request = blocks->xdrNumABlks;
+ found = 0;
+ foundat = 0;
+ start = vol->mdb.drAllocPtr;
+ end = vol->mdb.drNmAlBlks;
+ pt = start;
+ vbm = vol->vbm;
+
+ if (request == 0)
+ abort();
+
+ for (;;)
+ {
+ unsigned int mark;
+
+ /* skip blocks in use */
+
+ while (pt < end && BMTST(vbm, pt))
+ ++pt;
+
+ if (wrap && pt >= start)
+ break;
+
+ /* count blocks not in use */
+
+ mark = pt;
+ while (pt < end && pt - mark < request && ! BMTST(vbm, pt))
+ ++pt;
+
+ if (pt - mark > found)
+ {
+ found = pt - mark;
+ foundat = mark;
+ }
+
+ if (pt == end)
+ pt = 0, wrap = 1;
+
+ if (found == request)
+ break;
+ }
+
+ if (found == 0 || found > vol->mdb.drFreeBks)
+ {
+ ERROR(EIO, "bad volume bitmap or free block count");
+ return -1;
+ }
+
+ blocks->xdrStABN = foundat;
+ blocks->xdrNumABlks = found;
+
+ vol->mdb.drAllocPtr = pt;
+ vol->mdb.drFreeBks -= found;
+
+ for (pt = foundat; pt < foundat + found; ++pt)
+ BMSET(vbm, pt);
+
+ vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;
+
+ return 0;
+}
+
+/*
+ * NAME: vol->freeblocks()
+ * DESCRIPTION: deallocate a contiguous range of blocks
+ */
+void v_freeblocks(hfsvol *vol, ExtDescriptor *blocks)
+{
+ unsigned int start, len, pt;
+ block *vbm;
+
+ start = blocks->xdrStABN;
+ len = blocks->xdrNumABlks;
+ vbm = vol->vbm;
+
+ vol->mdb.drFreeBks += len;
+
+ for (pt = start; pt < start + len; ++pt)
+ BMCLR(vbm, pt);
+
+ vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;
+}
+
+/*
+ * NAME: vol->resolve()
+ * DESCRIPTION: translate a pathname; return catalog information
+ */
+int v_resolve(hfsvol **vol, char *path, CatDataRec *data, long *parid,
+ char *fname, node *np)
+{
+ long dirid;
+ char name[HFS_MAX_FLEN + 1], *nptr;
+ int found;
+
+ if (*path == 0)
+ {
+ ERROR(ENOENT, "empty path");
+ return -1;
+ }
+
+ if (parid)
+ *parid = 0;
+
+ nptr = strchr(path, ':');
+
+ if (*path == ':' || nptr == 0)
+ {
+ dirid = (*vol)->cwd; /* relative path */
+
+ if (*path == ':')
+ ++path;
+
+ if (*path == 0)
+ {
+ found = v_getdthread(*vol, dirid, data, 0);
+ if (found <= 0)
+ return found;
+
+ if (parid)
+ *parid = data->u.dthd.thdParID;
+
+ return v_catsearch(*vol, data->u.dthd.thdParID,
+ data->u.dthd.thdCName, data, fname, np);
+ }
+ }
+ else
+ {
+ hfsvol *check;
+
+ dirid = HFS_CNID_ROOTPAR; /* absolute path */
+
+ if (nptr - path > HFS_MAX_VLEN)
+ {
+ ERROR(ENAMETOOLONG, 0);
+ return -1;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ for (;;)
+ {
+ while (*path == ':')
+ {
+ ++path;
+
+ found = v_getdthread(*vol, dirid, data, 0);
+ if (found <= 0)
+ return found;
+
+ dirid = data->u.dthd.thdParID;
+ }
+
+ if (*path == 0)
+ {
+ found = v_getdthread(*vol, dirid, data, 0);
+ if (found <= 0)
+ return found;
+
+ if (parid)
+ *parid = data->u.dthd.thdParID;
+
+ return v_catsearch(*vol, data->u.dthd.thdParID,
+ data->u.dthd.thdCName, data, fname, np);
+ }
+
+ nptr = name;
+ while (nptr < name + sizeof(name) - 1 && *path && *path != ':')
+ *nptr++ = *path++;
+
+ if (*path && *path != ':')
+ {
+ ERROR(ENAMETOOLONG, 0);
+ return -1;
+ }
+
+ *nptr = 0;
+ if (*path == ':')
+ ++path;
+
+ if (parid)
+ *parid = dirid;
+
+ found = v_catsearch(*vol, dirid, name, data, fname, np);
+ if (found < 0)
+ return -1;
+
+ if (found == 0)
+ {
+ if (*path && parid)
+ *parid = 0;
+
+ if (*path == 0 && fname)
+ strcpy(fname, name);
+
+ return 0;
+ }
+
+ switch (data->cdrType)
+ {
+ case cdrDirRec:
+ if (*path == 0)
+ return 1;
+
+ dirid = data->u.dir.dirDirID;
+ break;
+
+ case cdrFilRec:
+ if (*path == 0)
+ return 1;
+
+ ERROR(ENOTDIR, "invalid pathname");
+ return -1;
+
+ default:
+ ERROR(EIO, "unexpected catalog record");
+ return -1;
+ }
+ }
+}
+
+/*
+ * NAME: vol->destruct()
+ * DESCRIPTION: free memory consumed by a volume descriptor
+ */
+void v_destruct(hfsvol *vol)
+{
+ FREE(vol->vbm);
+
+ FREE(vol->ext.map);
+ FREE(vol->cat.map);
+
+ FREE(vol);
+}
+
+/*
+ * NAME: vol->getvol()
+ * DESCRIPTION: validate a volume reference
+ */
+int v_getvol(hfsvol **vol)
+{
+ if (*vol == 0)
+ {
+ if (hfs_curvol == 0)
+ {
+ ERROR(EINVAL, "no volume is current");
+ return -1;
+ }
+
+ *vol = hfs_curvol;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: vol->flush()
+ * DESCRIPTION: flush all pending changes (B*-tree, MDB, VBM) to disk
+ */
+int v_flush(hfsvol *vol, int umounting)
+{
+ if (! (vol->flags & HFS_READONLY))
+ {
+ if ((vol->ext.flags & HFS_UPDATE_BTHDR) &&
+ bt_writehdr(&vol->ext) < 0)
+ return -1;
+
+ if ((vol->cat.flags & HFS_UPDATE_BTHDR) &&
+ bt_writehdr(&vol->cat) < 0)
+ return -1;
+
+ if ((vol->flags & HFS_UPDATE_VBM) &&
+ l_writevbm(vol) < 0)
+ return -1;
+
+ if (umounting &&
+ ! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
+ {
+ vol->mdb.drAtrb |= HFS_ATRB_UMOUNTED;
+ vol->flags |= HFS_UPDATE_MDB;
+ }
+
+ if ((vol->flags & (HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB)) &&
+ l_writemdb(vol) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * NAME: vol->adjvalence()
+ * DESCRIPTION: update a volume's valence counts
+ */
+int v_adjvalence(hfsvol *vol, long parid, int isdir, int adj)
+{
+ node n;
+ CatDataRec data;
+
+ if (isdir)
+ vol->mdb.drDirCnt += adj;
+ else
+ vol->mdb.drFilCnt += adj;
+
+ vol->flags |= HFS_UPDATE_MDB;
+
+ if (parid == HFS_CNID_ROOTDIR)
+ {
+ if (isdir)
+ vol->mdb.drNmRtDirs += adj;
+ else
+ vol->mdb.drNmFls += adj;
+ }
+ else if (parid == HFS_CNID_ROOTPAR)
+ return 0;
+
+ if (v_getdthread(vol, parid, &data, 0) <= 0 ||
+ v_catsearch(vol, data.u.dthd.thdParID, data.u.dthd.thdCName,
+ &data, 0, &n) <= 0 ||
+ data.cdrType != cdrDirRec)
+ {
+ ERROR(EIO, "can't find parent directory");
+ return -1;
+ }
+
+ data.u.dir.dirVal += adj;
+ data.u.dir.dirMdDat = d_tomtime(time(0));
+
+ return v_putcatrec(&data, &n);
+}
+
+/*
+ * NAME: vol->newfolder()
+ * DESCRIPTION: create a new HFS folder
+ */
+int v_newfolder(hfsvol *vol, long parid, char *name)
+{
+ CatKeyRec key;
+ CatDataRec data;
+ long id;
+ unsigned char record[HFS_CATRECMAXLEN];
+ int i, reclen;
+
+ if (bt_space(&vol->cat, 2) < 0)
+ return -1;
+
+ id = vol->mdb.drNxtCNID++;
+ vol->flags |= HFS_UPDATE_MDB;
+
+ /* create directory record */
+
+ data.cdrType = cdrDirRec;
+ data.cdrResrv2 = 0;
+
+ data.u.dir.dirFlags = 0;
+ data.u.dir.dirVal = 0;
+ data.u.dir.dirDirID = id;
+ data.u.dir.dirCrDat = d_tomtime(time(0));
+ data.u.dir.dirMdDat = data.u.dir.dirCrDat;
+ data.u.dir.dirBkDat = 0;
+
+ memset(&data.u.dir.dirUsrInfo, 0, sizeof(data.u.dir.dirUsrInfo));
+ memset(&data.u.dir.dirFndrInfo, 0, sizeof(data.u.dir.dirFndrInfo));
+ for (i = 0; i < 4; ++i)
+ data.u.dir.dirResrv[i] = 0;
+
+ r_makecatkey(&key, parid, name);
+ r_packcatkey(&key, record, &reclen);
+ r_packcatdata(&data, HFS_RECDATA(record), &reclen);
+
+ if (bt_insert(&vol->cat, record, reclen) < 0)
+ return -1;
+
+ /* create thread record */
+
+ data.cdrType = cdrThdRec;
+ data.cdrResrv2 = 0;
+
+ data.u.dthd.thdResrv[0] = 0;
+ data.u.dthd.thdResrv[1] = 0;
+ data.u.dthd.thdParID = parid;
+ strcpy(data.u.dthd.thdCName, name);
+
+ r_makecatkey(&key, id, "");
+ r_packcatkey(&key, record, &reclen);
+ r_packcatdata(&data, HFS_RECDATA(record), &reclen);
+
+ if (bt_insert(&vol->cat, record, reclen) < 0 ||
+ v_adjvalence(vol, parid, 1, 1) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * NAME: markexts()
+ * DESCRIPTION: set bits from an extent record in the volume bitmap
+ */
+static
+void markexts(block *vbm, ExtDataRec *exts)
+{
+ int i;
+ unsigned int start, len;
+
+ for (i = 0; i < 3; ++i)
+ {
+ for (start = (*exts)[i].xdrStABN,
+ len = (*exts)[i].xdrNumABlks; len--; ++start)
+ BMSET(vbm, start);
+ }
+}
+
+/*
+ * NAME: vol->scavenge()
+ * DESCRIPTION: safeguard blocks in the volume bitmap
+ */
+int v_scavenge(hfsvol *vol)
+{
+ block *vbm = vol->vbm;
+ node n;
+ unsigned int pt, blks;
+
+ if (vbm == 0)
+ return 0;
+
+ markexts(vbm, &vol->mdb.drXTExtRec);
+ markexts(vbm, &vol->mdb.drCTExtRec);
+
+ vol->flags |= HFS_UPDATE_VBM;
+
+ /* scavenge the extents overflow file */
+
+ n.bt = &vol->ext;
+ n.nnum = vol->ext.hdr.bthFNode;
+
+ if (n.nnum > 0)
+ {
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.rnum = 0;
+
+ for (;;)
+ {
+ ExtDataRec data;
+ unsigned char *ptr;
+
+ while (n.rnum >= (int)n.nd.ndNRecs)
+ {
+ n.nnum = n.nd.ndFLink;
+ if (n.nnum == 0)
+ break;
+
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.rnum = 0;
+ }
+
+ if (n.nnum == 0)
+ break;
+
+ ptr = HFS_NODEREC(n, n.rnum);
+ r_unpackextdata(HFS_RECDATA(ptr), &data);
+
+ markexts(vbm, &data);
+
+ ++n.rnum;
+ }
+ }
+
+ /* scavenge the catalog file */
+
+ n.bt = &vol->cat;
+ n.nnum = vol->cat.hdr.bthFNode;
+
+ if (n.nnum > 0)
+ {
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.rnum = 0;
+
+ for (;;)
+ {
+ CatDataRec data;
+ unsigned char *ptr;
+
+ while (n.rnum >= (int)n.nd.ndNRecs)
+ {
+ n.nnum = n.nd.ndFLink;
+ if (n.nnum == 0)
+ break;
+
+ if (bt_getnode(&n) < 0)
+ return -1;
+
+ n.rnum = 0;
+ }
+
+ if (n.nnum == 0)
+ break;
+
+ ptr = HFS_NODEREC(n, n.rnum);
+ r_unpackcatdata(HFS_RECDATA(ptr), &data);
+
+ if (data.cdrType == cdrFilRec)
+ {
+ markexts(vbm, &data.u.fil.filExtRec);
+ markexts(vbm, &data.u.fil.filRExtRec);
+ }
+
+ ++n.rnum;
+ }
+ }
+
+ for (blks = 0, pt = vol->mdb.drNmAlBlks; pt--; )
+ {
+ if (! BMTST(vbm, pt))
+ ++blks;
+ }
+
+ if (vol->mdb.drFreeBks != blks)
+ {
+ vol->mdb.drFreeBks = blks;
+ vol->flags |= HFS_UPDATE_MDB;
+ }
+
+ return 0;
+}
diff --git a/libhfs_iso/volume.h b/libhfs_iso/volume.h
new file mode 100644
index 0000000..2cc6005
--- /dev/null
+++ b/libhfs_iso/volume.h
@@ -0,0 +1,58 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)volume.h 1.1 00/03/05 joerg */
+/*
+ * hfsutils - tools for reading and writing Macintosh HFS volumes
+ * Copyright (C) 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int v_catsearch(hfsvol *, long, char *, CatDataRec *, char *, node *);
+int v_extsearch(hfsfile *, unsigned int, ExtDataRec *, node *);
+
+int v_getthread(hfsvol *, 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(CatDataRec *, node *);
+int v_putextrec(ExtDataRec *, node *);
+
+int v_allocblocks(hfsvol *, ExtDescriptor *);
+void v_freeblocks(hfsvol *, ExtDescriptor *);
+
+int v_resolve(hfsvol **, char *, CatDataRec *, long *, char *, node *);
+
+void v_destruct(hfsvol *);
+int v_getvol(hfsvol **);
+int v_flush(hfsvol *, int);
+
+int v_adjvalence(hfsvol *, long, int, int);
+int v_newfolder(hfsvol *, long, char *);
+
+int v_scavenge(hfsvol *);