diff options
Diffstat (limited to 'libhfs_iso/low.c')
-rw-r--r-- | libhfs_iso/low.c | 529 |
1 files changed, 529 insertions, 0 deletions
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; +} |