/* * libhfs - library for reading and writing Macintosh HFS volumes * Copyright (C) 1996-1998 Robert Leslie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: record.c,v 1.9 1998/11/02 22:09:07 rob Exp $ */ # include # include "libhfs.h" # include "record.h" # include "data.h" /* * NAME: record->packcatkey() * DESCRIPTION: pack a catalog record key */ void r_packcatkey(const CatKeyRec *key, byte *pkey, unsigned int *len) { const byte *start = pkey; d_storesb(&pkey, key->ckrKeyLen); d_storesb(&pkey, key->ckrResrv1); d_storeul(&pkey, key->ckrParID); d_storestr(&pkey, key->ckrCName, sizeof(key->ckrCName)); if (len) *len = HFS_RECKEYSKIP(start); } /* * NAME: record->unpackcatkey() * DESCRIPTION: unpack a catalog record key */ void r_unpackcatkey(const byte *pkey, CatKeyRec *key) { d_fetchsb(&pkey, &key->ckrKeyLen); d_fetchsb(&pkey, &key->ckrResrv1); d_fetchul(&pkey, &key->ckrParID); d_fetchstr(&pkey, key->ckrCName, sizeof(key->ckrCName)); } /* * NAME: record->packextkey() * DESCRIPTION: pack an extents record key */ void r_packextkey(const ExtKeyRec *key, byte *pkey, unsigned int *len) { const byte *start = pkey; d_storesb(&pkey, key->xkrKeyLen); d_storesb(&pkey, key->xkrFkType); d_storeul(&pkey, key->xkrFNum); d_storeuw(&pkey, key->xkrFABN); if (len) *len = HFS_RECKEYSKIP(start); } /* * NAME: record->unpackextkey() * DESCRIPTION: unpack an extents record key */ void r_unpackextkey(const byte *pkey, ExtKeyRec *key) { d_fetchsb(&pkey, &key->xkrKeyLen); d_fetchsb(&pkey, &key->xkrFkType); d_fetchul(&pkey, &key->xkrFNum); d_fetchuw(&pkey, &key->xkrFABN); } /* * NAME: record->comparecatkeys() * DESCRIPTION: compare two (packed) catalog record keys */ int r_comparecatkeys(const CatKeyRec *key1, const CatKeyRec *key2) { int diff; diff = key1->ckrParID - key2->ckrParID; if (diff) return diff; return d_relstring(key1->ckrCName, key2->ckrCName); } /* * NAME: record->compareextkeys() * DESCRIPTION: compare two (packed) extents record keys */ int r_compareextkeys(const ExtKeyRec *key1, const ExtKeyRec *key2) { int diff; diff = key1->xkrFNum - key2->xkrFNum; if (diff) return diff; diff = (unsigned char) key1->xkrFkType - (unsigned char) key2->xkrFkType; if (diff) return diff; return key1->xkrFABN - key2->xkrFABN; } /* * NAME: record->packcatdata() * DESCRIPTION: pack catalog record data */ void r_packcatdata(const CatDataRec *data, byte *pdata, unsigned int *len) { const byte *start = pdata; int i; d_storesb(&pdata, data->cdrType); d_storesb(&pdata, data->cdrResrv2); switch (data->cdrType) { case cdrDirRec: d_storesw(&pdata, data->u.dir.dirFlags); d_storeuw(&pdata, data->u.dir.dirVal); d_storeul(&pdata, data->u.dir.dirDirID); d_storesl(&pdata, data->u.dir.dirCrDat); d_storesl(&pdata, data->u.dir.dirMdDat); d_storesl(&pdata, data->u.dir.dirBkDat); d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.top); d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.left); d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.bottom); d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.right); d_storesw(&pdata, data->u.dir.dirUsrInfo.frFlags); d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.v); d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.h); d_storesw(&pdata, data->u.dir.dirUsrInfo.frView); d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.v); d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.h); d_storesl(&pdata, data->u.dir.dirFndrInfo.frOpenChain); d_storesw(&pdata, data->u.dir.dirFndrInfo.frUnused); d_storesw(&pdata, data->u.dir.dirFndrInfo.frComment); d_storesl(&pdata, data->u.dir.dirFndrInfo.frPutAway); for (i = 0; i < 4; ++i) d_storesl(&pdata, data->u.dir.dirResrv[i]); break; case cdrFilRec: d_storesb(&pdata, data->u.fil.filFlags); d_storesb(&pdata, data->u.fil.filTyp); d_storesl(&pdata, data->u.fil.filUsrWds.fdType); d_storesl(&pdata, data->u.fil.filUsrWds.fdCreator); d_storesw(&pdata, data->u.fil.filUsrWds.fdFlags); d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.v); d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.h); d_storesw(&pdata, data->u.fil.filUsrWds.fdFldr); d_storeul(&pdata, data->u.fil.filFlNum); d_storeuw(&pdata, data->u.fil.filStBlk); d_storeul(&pdata, data->u.fil.filLgLen); d_storeul(&pdata, data->u.fil.filPyLen); d_storeuw(&pdata, data->u.fil.filRStBlk); d_storeul(&pdata, data->u.fil.filRLgLen); d_storeul(&pdata, data->u.fil.filRPyLen); d_storesl(&pdata, data->u.fil.filCrDat); d_storesl(&pdata, data->u.fil.filMdDat); d_storesl(&pdata, data->u.fil.filBkDat); d_storesw(&pdata, data->u.fil.filFndrInfo.fdIconID); for (i = 0; i < 4; ++i) d_storesw(&pdata, data->u.fil.filFndrInfo.fdUnused[i]); d_storesw(&pdata, data->u.fil.filFndrInfo.fdComment); d_storesl(&pdata, data->u.fil.filFndrInfo.fdPutAway); d_storeuw(&pdata, data->u.fil.filClpSize); for (i = 0; i < 3; ++i) { d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrStABN); d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrNumABlks); } for (i = 0; i < 3; ++i) { d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrStABN); d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks); } d_storesl(&pdata, data->u.fil.filResrv); break; case cdrThdRec: for (i = 0; i < 2; ++i) d_storesl(&pdata, data->u.dthd.thdResrv[i]); d_storeul(&pdata, data->u.dthd.thdParID); d_storestr(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName)); break; case cdrFThdRec: for (i = 0; i < 2; ++i) d_storesl(&pdata, data->u.fthd.fthdResrv[i]); d_storeul(&pdata, data->u.fthd.fthdParID); d_storestr(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName)); break; default: ASSERT(0); } if (len) *len += pdata - start; } /* * NAME: record->unpackcatdata() * DESCRIPTION: unpack catalog record data */ void r_unpackcatdata(const byte *pdata, CatDataRec *data) { int i; d_fetchsb(&pdata, &data->cdrType); d_fetchsb(&pdata, &data->cdrResrv2); switch (data->cdrType) { case cdrDirRec: d_fetchsw(&pdata, &data->u.dir.dirFlags); d_fetchuw(&pdata, &data->u.dir.dirVal); d_fetchul(&pdata, &data->u.dir.dirDirID); d_fetchsl(&pdata, &data->u.dir.dirCrDat); d_fetchsl(&pdata, &data->u.dir.dirMdDat); d_fetchsl(&pdata, &data->u.dir.dirBkDat); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.top); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.left); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.right); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frFlags); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h); d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frView); d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v); d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h); d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain); d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frUnused); d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frComment); d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frPutAway); for (i = 0; i < 4; ++i) d_fetchsl(&pdata, &data->u.dir.dirResrv[i]); break; case cdrFilRec: d_fetchsb(&pdata, &data->u.fil.filFlags); d_fetchsb(&pdata, &data->u.fil.filTyp); d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdType); d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdCreator); d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFlags); d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.v); d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.h); d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFldr); d_fetchul(&pdata, &data->u.fil.filFlNum); d_fetchuw(&pdata, &data->u.fil.filStBlk); d_fetchul(&pdata, &data->u.fil.filLgLen); d_fetchul(&pdata, &data->u.fil.filPyLen); d_fetchuw(&pdata, &data->u.fil.filRStBlk); d_fetchul(&pdata, &data->u.fil.filRLgLen); d_fetchul(&pdata, &data->u.fil.filRPyLen); d_fetchsl(&pdata, &data->u.fil.filCrDat); d_fetchsl(&pdata, &data->u.fil.filMdDat); d_fetchsl(&pdata, &data->u.fil.filBkDat); d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdIconID); for (i = 0; i < 4; ++i) d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]); d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdComment); d_fetchsl(&pdata, &data->u.fil.filFndrInfo.fdPutAway); d_fetchuw(&pdata, &data->u.fil.filClpSize); for (i = 0; i < 3; ++i) { d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrStABN); d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrNumABlks); } for (i = 0; i < 3; ++i) { d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrStABN); d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrNumABlks); } d_fetchsl(&pdata, &data->u.fil.filResrv); break; case cdrThdRec: for (i = 0; i < 2; ++i) d_fetchsl(&pdata, &data->u.dthd.thdResrv[i]); d_fetchul(&pdata, &data->u.dthd.thdParID); d_fetchstr(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName)); break; case cdrFThdRec: for (i = 0; i < 2; ++i) d_fetchsl(&pdata, &data->u.fthd.fthdResrv[i]); d_fetchul(&pdata, &data->u.fthd.fthdParID); d_fetchstr(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName)); break; default: ASSERT(0); } } /* * NAME: record->packextdata() * DESCRIPTION: pack extent record data */ void r_packextdata(const ExtDataRec *data, byte *pdata, unsigned int *len) { const byte *start = pdata; int i; for (i = 0; i < 3; ++i) { d_storeuw(&pdata, (*data)[i].xdrStABN); d_storeuw(&pdata, (*data)[i].xdrNumABlks); } if (len) *len += pdata - start; } /* * NAME: record->unpackextdata() * DESCRIPTION: unpack extent record data */ void r_unpackextdata(const byte *pdata, ExtDataRec *data) { int i; for (i = 0; i < 3; ++i) { d_fetchuw(&pdata, &(*data)[i].xdrStABN); d_fetchuw(&pdata, &(*data)[i].xdrNumABlks); } } /* * NAME: record->makecatkey() * DESCRIPTION: construct a catalog record key */ void r_makecatkey(CatKeyRec *key, unsigned long parid, const char *name) { int len; len = strlen(name) + 1; key->ckrKeyLen = 0x05 + len + (len & 1); key->ckrResrv1 = 0; key->ckrParID = parid; strcpy(key->ckrCName, name); } /* * NAME: record->makeextkey() * DESCRIPTION: construct an extents record key */ void r_makeextkey(ExtKeyRec *key, int fork, unsigned long fnum, unsigned int fabn) { key->xkrKeyLen = 0x07; key->xkrFkType = fork; key->xkrFNum = fnum; key->xkrFABN = fabn; } /* * NAME: record->packcatrec() * DESCRIPTION: create a packed catalog record */ void r_packcatrec(const CatKeyRec *key, const CatDataRec *data, byte *precord, unsigned int *len) { r_packcatkey(key, precord, len); r_packcatdata(data, HFS_RECDATA(precord), len); } /* * NAME: record->packextrec() * DESCRIPTION: create a packed extents record */ void r_packextrec(const ExtKeyRec *key, const ExtDataRec *data, byte *precord, unsigned int *len) { r_packextkey(key, precord, len); r_packextdata(data, HFS_RECDATA(precord), len); } /* * NAME: record->packdirent() * DESCRIPTION: make changes to a catalog record */ void r_packdirent(CatDataRec *data, const hfsdirent *ent) { switch (data->cdrType) { case cdrDirRec: data->u.dir.dirCrDat = d_mtime(ent->crdate); data->u.dir.dirMdDat = d_mtime(ent->mddate); data->u.dir.dirBkDat = d_mtime(ent->bkdate); data->u.dir.dirUsrInfo.frFlags = ent->fdflags; data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v; data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h; data->u.dir.dirUsrInfo.frRect.top = ent->u.dir.rect.top; data->u.dir.dirUsrInfo.frRect.left = ent->u.dir.rect.left; data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom; data->u.dir.dirUsrInfo.frRect.right = ent->u.dir.rect.right; break; case cdrFilRec: if (ent->flags & HFS_ISLOCKED) data->u.fil.filFlags |= (1 << 0); else data->u.fil.filFlags &= ~(1 << 0); data->u.fil.filCrDat = d_mtime(ent->crdate); data->u.fil.filMdDat = d_mtime(ent->mddate); data->u.fil.filBkDat = d_mtime(ent->bkdate); data->u.fil.filUsrWds.fdFlags = ent->fdflags; data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v; data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h; data->u.fil.filUsrWds.fdType = d_getsl((const unsigned char *) ent->u.file.type); data->u.fil.filUsrWds.fdCreator = d_getsl((const unsigned char *) ent->u.file.creator); break; } } /* * NAME: record->unpackdirent() * DESCRIPTION: unpack catalog information into hfsdirent structure */ void r_unpackdirent(unsigned long parid, const char *name, const CatDataRec *data, hfsdirent *ent) { strcpy(ent->name, name); ent->parid = parid; switch (data->cdrType) { case cdrDirRec: ent->flags = HFS_ISDIR; ent->cnid = data->u.dir.dirDirID; ent->crdate = d_ltime(data->u.dir.dirCrDat); ent->mddate = d_ltime(data->u.dir.dirMdDat); ent->bkdate = d_ltime(data->u.dir.dirBkDat); ent->fdflags = data->u.dir.dirUsrInfo.frFlags; ent->fdlocation.v = data->u.dir.dirUsrInfo.frLocation.v; ent->fdlocation.h = data->u.dir.dirUsrInfo.frLocation.h; ent->u.dir.valence = data->u.dir.dirVal; ent->u.dir.rect.top = data->u.dir.dirUsrInfo.frRect.top; ent->u.dir.rect.left = data->u.dir.dirUsrInfo.frRect.left; ent->u.dir.rect.bottom = data->u.dir.dirUsrInfo.frRect.bottom; ent->u.dir.rect.right = data->u.dir.dirUsrInfo.frRect.right; break; case cdrFilRec: ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0; ent->cnid = data->u.fil.filFlNum; ent->crdate = d_ltime(data->u.fil.filCrDat); ent->mddate = d_ltime(data->u.fil.filMdDat); ent->bkdate = d_ltime(data->u.fil.filBkDat); ent->fdflags = data->u.fil.filUsrWds.fdFlags; ent->fdlocation.v = data->u.fil.filUsrWds.fdLocation.v; ent->fdlocation.h = data->u.fil.filUsrWds.fdLocation.h; ent->u.file.dsize = data->u.fil.filLgLen; ent->u.file.rsize = data->u.fil.filRLgLen; d_putsl((unsigned char *) ent->u.file.type, data->u.fil.filUsrWds.fdType); d_putsl((unsigned char *) ent->u.file.creator, data->u.fil.filUsrWds.fdCreator); ent->u.file.type[4] = ent->u.file.creator[4] = 0; break; } }