libhfs/record.c

554 lines
15 KiB
C

/*
* 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 <string.h>
# include "libhfs.h"
# include "record.h"
# include "data.h"
/*
* NAME: record->packcatkey()
* DESCRIPTION: pack a catalog record key
*/
void r_packcatkey(const CatKeyRec *key, byte *pkey, unsigned int *len)
{
const byte *start = pkey;
d_storesb(&pkey, key->ckrKeyLen);
d_storesb(&pkey, key->ckrResrv1);
d_storeul(&pkey, key->ckrParID);
d_storestr(&pkey, key->ckrCName, sizeof(key->ckrCName));
if (len)
*len = HFS_RECKEYSKIP(start);
}
/*
* NAME: record->unpackcatkey()
* DESCRIPTION: unpack a catalog record key
*/
void r_unpackcatkey(const byte *pkey, CatKeyRec *key)
{
d_fetchsb(&pkey, &key->ckrKeyLen);
d_fetchsb(&pkey, &key->ckrResrv1);
d_fetchul(&pkey, &key->ckrParID);
d_fetchstr(&pkey, key->ckrCName, sizeof(key->ckrCName));
}
/*
* NAME: record->packextkey()
* DESCRIPTION: pack an extents record key
*/
void r_packextkey(const ExtKeyRec *key, byte *pkey, unsigned int *len)
{
const byte *start = pkey;
d_storesb(&pkey, key->xkrKeyLen);
d_storesb(&pkey, key->xkrFkType);
d_storeul(&pkey, key->xkrFNum);
d_storeuw(&pkey, key->xkrFABN);
if (len)
*len = HFS_RECKEYSKIP(start);
}
/*
* NAME: record->unpackextkey()
* DESCRIPTION: unpack an extents record key
*/
void r_unpackextkey(const byte *pkey, ExtKeyRec *key)
{
d_fetchsb(&pkey, &key->xkrKeyLen);
d_fetchsb(&pkey, &key->xkrFkType);
d_fetchul(&pkey, &key->xkrFNum);
d_fetchuw(&pkey, &key->xkrFABN);
}
/*
* NAME: record->comparecatkeys()
* DESCRIPTION: compare two (packed) catalog record keys
*/
int r_comparecatkeys(const CatKeyRec *key1, const CatKeyRec *key2)
{
int diff;
diff = key1->ckrParID - key2->ckrParID;
if (diff)
return diff;
return d_relstring(key1->ckrCName, key2->ckrCName);
}
/*
* NAME: record->compareextkeys()
* DESCRIPTION: compare two (packed) extents record keys
*/
int r_compareextkeys(const ExtKeyRec *key1, const ExtKeyRec *key2)
{
int diff;
diff = key1->xkrFNum - key2->xkrFNum;
if (diff)
return diff;
diff = (unsigned char) key1->xkrFkType -
(unsigned char) key2->xkrFkType;
if (diff)
return diff;
return key1->xkrFABN - key2->xkrFABN;
}
/*
* NAME: record->packcatdata()
* DESCRIPTION: pack catalog record data
*/
void r_packcatdata(const CatDataRec *data, byte *pdata, unsigned int *len)
{
const byte *start = pdata;
int i;
d_storesb(&pdata, data->cdrType);
d_storesb(&pdata, data->cdrResrv2);
switch (data->cdrType)
{
case cdrDirRec:
d_storesw(&pdata, data->u.dir.dirFlags);
d_storeuw(&pdata, data->u.dir.dirVal);
d_storeul(&pdata, data->u.dir.dirDirID);
d_storesl(&pdata, data->u.dir.dirCrDat);
d_storesl(&pdata, data->u.dir.dirMdDat);
d_storesl(&pdata, data->u.dir.dirBkDat);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.top);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.left);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.bottom);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.right);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frFlags);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.v);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.h);
d_storesw(&pdata, data->u.dir.dirUsrInfo.frView);
d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.v);
d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.h);
d_storesl(&pdata, data->u.dir.dirFndrInfo.frOpenChain);
d_storesw(&pdata, data->u.dir.dirFndrInfo.frUnused);
d_storesw(&pdata, data->u.dir.dirFndrInfo.frComment);
d_storesl(&pdata, data->u.dir.dirFndrInfo.frPutAway);
for (i = 0; i < 4; ++i)
d_storesl(&pdata, data->u.dir.dirResrv[i]);
break;
case cdrFilRec:
d_storesb(&pdata, data->u.fil.filFlags);
d_storesb(&pdata, data->u.fil.filTyp);
d_storesl(&pdata, data->u.fil.filUsrWds.fdType);
d_storesl(&pdata, data->u.fil.filUsrWds.fdCreator);
d_storesw(&pdata, data->u.fil.filUsrWds.fdFlags);
d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.v);
d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.h);
d_storesw(&pdata, data->u.fil.filUsrWds.fdFldr);
d_storeul(&pdata, data->u.fil.filFlNum);
d_storeuw(&pdata, data->u.fil.filStBlk);
d_storeul(&pdata, data->u.fil.filLgLen);
d_storeul(&pdata, data->u.fil.filPyLen);
d_storeuw(&pdata, data->u.fil.filRStBlk);
d_storeul(&pdata, data->u.fil.filRLgLen);
d_storeul(&pdata, data->u.fil.filRPyLen);
d_storesl(&pdata, data->u.fil.filCrDat);
d_storesl(&pdata, data->u.fil.filMdDat);
d_storesl(&pdata, data->u.fil.filBkDat);
d_storesw(&pdata, data->u.fil.filFndrInfo.fdIconID);
for (i = 0; i < 4; ++i)
d_storesw(&pdata, data->u.fil.filFndrInfo.fdUnused[i]);
d_storesw(&pdata, data->u.fil.filFndrInfo.fdComment);
d_storesl(&pdata, data->u.fil.filFndrInfo.fdPutAway);
d_storeuw(&pdata, data->u.fil.filClpSize);
for (i = 0; i < 3; ++i)
{
d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrStABN);
d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrNumABlks);
}
for (i = 0; i < 3; ++i)
{
d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrStABN);
d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks);
}
d_storesl(&pdata, data->u.fil.filResrv);
break;
case cdrThdRec:
for (i = 0; i < 2; ++i)
d_storesl(&pdata, data->u.dthd.thdResrv[i]);
d_storeul(&pdata, data->u.dthd.thdParID);
d_storestr(&pdata, data->u.dthd.thdCName,
sizeof(data->u.dthd.thdCName));
break;
case cdrFThdRec:
for (i = 0; i < 2; ++i)
d_storesl(&pdata, data->u.fthd.fthdResrv[i]);
d_storeul(&pdata, data->u.fthd.fthdParID);
d_storestr(&pdata, data->u.fthd.fthdCName,
sizeof(data->u.fthd.fthdCName));
break;
default:
ASSERT(0);
}
if (len)
*len += pdata - start;
}
/*
* NAME: record->unpackcatdata()
* DESCRIPTION: unpack catalog record data
*/
void r_unpackcatdata(const byte *pdata, CatDataRec *data)
{
int i;
d_fetchsb(&pdata, &data->cdrType);
d_fetchsb(&pdata, &data->cdrResrv2);
switch (data->cdrType)
{
case cdrDirRec:
d_fetchsw(&pdata, &data->u.dir.dirFlags);
d_fetchuw(&pdata, &data->u.dir.dirVal);
d_fetchul(&pdata, &data->u.dir.dirDirID);
d_fetchsl(&pdata, &data->u.dir.dirCrDat);
d_fetchsl(&pdata, &data->u.dir.dirMdDat);
d_fetchsl(&pdata, &data->u.dir.dirBkDat);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.top);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.left);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.right);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frFlags);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h);
d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frView);
d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v);
d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h);
d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain);
d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frUnused);
d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frComment);
d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frPutAway);
for (i = 0; i < 4; ++i)
d_fetchsl(&pdata, &data->u.dir.dirResrv[i]);
break;
case cdrFilRec:
d_fetchsb(&pdata, &data->u.fil.filFlags);
d_fetchsb(&pdata, &data->u.fil.filTyp);
d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdType);
d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdCreator);
d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFlags);
d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.v);
d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.h);
d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFldr);
d_fetchul(&pdata, &data->u.fil.filFlNum);
d_fetchuw(&pdata, &data->u.fil.filStBlk);
d_fetchul(&pdata, &data->u.fil.filLgLen);
d_fetchul(&pdata, &data->u.fil.filPyLen);
d_fetchuw(&pdata, &data->u.fil.filRStBlk);
d_fetchul(&pdata, &data->u.fil.filRLgLen);
d_fetchul(&pdata, &data->u.fil.filRPyLen);
d_fetchsl(&pdata, &data->u.fil.filCrDat);
d_fetchsl(&pdata, &data->u.fil.filMdDat);
d_fetchsl(&pdata, &data->u.fil.filBkDat);
d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdIconID);
for (i = 0; i < 4; ++i)
d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]);
d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdComment);
d_fetchsl(&pdata, &data->u.fil.filFndrInfo.fdPutAway);
d_fetchuw(&pdata, &data->u.fil.filClpSize);
for (i = 0; i < 3; ++i)
{
d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrStABN);
d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrNumABlks);
}
for (i = 0; i < 3; ++i)
{
d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrStABN);
d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrNumABlks);
}
d_fetchsl(&pdata, &data->u.fil.filResrv);
break;
case cdrThdRec:
for (i = 0; i < 2; ++i)
d_fetchsl(&pdata, &data->u.dthd.thdResrv[i]);
d_fetchul(&pdata, &data->u.dthd.thdParID);
d_fetchstr(&pdata, data->u.dthd.thdCName,
sizeof(data->u.dthd.thdCName));
break;
case cdrFThdRec:
for (i = 0; i < 2; ++i)
d_fetchsl(&pdata, &data->u.fthd.fthdResrv[i]);
d_fetchul(&pdata, &data->u.fthd.fthdParID);
d_fetchstr(&pdata, data->u.fthd.fthdCName,
sizeof(data->u.fthd.fthdCName));
break;
default:
ASSERT(0);
}
}
/*
* NAME: record->packextdata()
* DESCRIPTION: pack extent record data
*/
void r_packextdata(const ExtDataRec *data, byte *pdata, unsigned int *len)
{
const byte *start = pdata;
int i;
for (i = 0; i < 3; ++i)
{
d_storeuw(&pdata, (*data)[i].xdrStABN);
d_storeuw(&pdata, (*data)[i].xdrNumABlks);
}
if (len)
*len += pdata - start;
}
/*
* NAME: record->unpackextdata()
* DESCRIPTION: unpack extent record data
*/
void r_unpackextdata(const byte *pdata, ExtDataRec *data)
{
int i;
for (i = 0; i < 3; ++i)
{
d_fetchuw(&pdata, &(*data)[i].xdrStABN);
d_fetchuw(&pdata, &(*data)[i].xdrNumABlks);
}
}
/*
* NAME: record->makecatkey()
* DESCRIPTION: construct a catalog record key
*/
void r_makecatkey(CatKeyRec *key, unsigned long parid, const char *name)
{
int len;
len = strlen(name) + 1;
key->ckrKeyLen = 0x05 + len + (len & 1);
key->ckrResrv1 = 0;
key->ckrParID = parid;
strcpy(key->ckrCName, name);
}
/*
* NAME: record->makeextkey()
* DESCRIPTION: construct an extents record key
*/
void r_makeextkey(ExtKeyRec *key,
int fork, unsigned long fnum, unsigned int fabn)
{
key->xkrKeyLen = 0x07;
key->xkrFkType = fork;
key->xkrFNum = fnum;
key->xkrFABN = fabn;
}
/*
* NAME: record->packcatrec()
* DESCRIPTION: create a packed catalog record
*/
void r_packcatrec(const CatKeyRec *key, const CatDataRec *data,
byte *precord, unsigned int *len)
{
r_packcatkey(key, precord, len);
r_packcatdata(data, HFS_RECDATA(precord), len);
}
/*
* NAME: record->packextrec()
* DESCRIPTION: create a packed extents record
*/
void r_packextrec(const ExtKeyRec *key, const ExtDataRec *data,
byte *precord, unsigned int *len)
{
r_packextkey(key, precord, len);
r_packextdata(data, HFS_RECDATA(precord), len);
}
/*
* NAME: record->packdirent()
* DESCRIPTION: make changes to a catalog record
*/
void r_packdirent(CatDataRec *data, const hfsdirent *ent)
{
switch (data->cdrType)
{
case cdrDirRec:
data->u.dir.dirCrDat = d_mtime(ent->crdate);
data->u.dir.dirMdDat = d_mtime(ent->mddate);
data->u.dir.dirBkDat = d_mtime(ent->bkdate);
data->u.dir.dirUsrInfo.frFlags = ent->fdflags;
data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v;
data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h;
data->u.dir.dirUsrInfo.frRect.top = ent->u.dir.rect.top;
data->u.dir.dirUsrInfo.frRect.left = ent->u.dir.rect.left;
data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom;
data->u.dir.dirUsrInfo.frRect.right = ent->u.dir.rect.right;
break;
case cdrFilRec:
if (ent->flags & HFS_ISLOCKED)
data->u.fil.filFlags |= (1 << 0);
else
data->u.fil.filFlags &= ~(1 << 0);
data->u.fil.filCrDat = d_mtime(ent->crdate);
data->u.fil.filMdDat = d_mtime(ent->mddate);
data->u.fil.filBkDat = d_mtime(ent->bkdate);
data->u.fil.filUsrWds.fdFlags = ent->fdflags;
data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v;
data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h;
data->u.fil.filUsrWds.fdType =
d_getsl((const unsigned char *) ent->u.file.type);
data->u.fil.filUsrWds.fdCreator =
d_getsl((const unsigned char *) ent->u.file.creator);
break;
}
}
/*
* NAME: record->unpackdirent()
* DESCRIPTION: unpack catalog information into hfsdirent structure
*/
void r_unpackdirent(unsigned long parid, const char *name,
const CatDataRec *data, hfsdirent *ent)
{
strcpy(ent->name, name);
ent->parid = parid;
switch (data->cdrType)
{
case cdrDirRec:
ent->flags = HFS_ISDIR;
ent->cnid = data->u.dir.dirDirID;
ent->crdate = d_ltime(data->u.dir.dirCrDat);
ent->mddate = d_ltime(data->u.dir.dirMdDat);
ent->bkdate = d_ltime(data->u.dir.dirBkDat);
ent->fdflags = data->u.dir.dirUsrInfo.frFlags;
ent->fdlocation.v = data->u.dir.dirUsrInfo.frLocation.v;
ent->fdlocation.h = data->u.dir.dirUsrInfo.frLocation.h;
ent->u.dir.valence = data->u.dir.dirVal;
ent->u.dir.rect.top = data->u.dir.dirUsrInfo.frRect.top;
ent->u.dir.rect.left = data->u.dir.dirUsrInfo.frRect.left;
ent->u.dir.rect.bottom = data->u.dir.dirUsrInfo.frRect.bottom;
ent->u.dir.rect.right = data->u.dir.dirUsrInfo.frRect.right;
break;
case cdrFilRec:
ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0;
ent->cnid = data->u.fil.filFlNum;
ent->crdate = d_ltime(data->u.fil.filCrDat);
ent->mddate = d_ltime(data->u.fil.filMdDat);
ent->bkdate = d_ltime(data->u.fil.filBkDat);
ent->fdflags = data->u.fil.filUsrWds.fdFlags;
ent->fdlocation.v = data->u.fil.filUsrWds.fdLocation.v;
ent->fdlocation.h = data->u.fil.filUsrWds.fdLocation.h;
ent->u.file.dsize = data->u.fil.filLgLen;
ent->u.file.rsize = data->u.fil.filRLgLen;
d_putsl((unsigned char *) ent->u.file.type,
data->u.fil.filUsrWds.fdType);
d_putsl((unsigned char *) ent->u.file.creator,
data->u.fil.filUsrWds.fdCreator);
ent->u.file.type[4] = ent->u.file.creator[4] = 0;
break;
}
}