home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 18
/
amigaformatcd18.iso
/
-in_the_mag-
/
emulation
/
emus
/
handlers
/
amicdfilesystem
/
src
/
hfs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-31
|
20KB
|
849 lines
/* hfs.c:
*
* Support for the Macintosh HFS filing system.
*
* Modified by Nicola Salmoria.
*
* ----------------------------------------------------------------------
* This code is (C) Copyright 1993,1994 by Frank Munkert.
* All rights reserved.
* This software may be freely distributed and redistributed for
* non-commercial purposes, provided this notice is included.
* ----------------------------------------------------------------------
* [History removed]
*/
#include <stdlib.h>
#include <string.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include "cdrom.h"
#include "generic.h"
#include "hfs.h"
typedef struct hfs_vol_info {
t_mdb mdb;
int start_block;
t_ulong root_node;
} t_hfs_vol_info;
typedef struct hfs_obj_info {
t_bool data_fork;
t_ulong parent_id;
char name[50];
t_catalog_record cat_rec;
} t_hfs_obj_info;
typedef struct leaf_record_pos {
t_ulong node;
t_ushort record;
t_node_descr node_descr;
t_catalog_record cat_rec;
t_leaf_record leaf_rec;
char pad[32]; /* space for name from t_leaf_record */
} t_leaf_record_pos;
#define VOL(vol,tag) (((t_hfs_vol_info *)(vol->vol_info))->tag)
#define OBJ(obj,tag) (((t_hfs_obj_info *)(obj->obj_info))->tag)
/* Number of seconds betweem 01-Jan-1904 and 01-Jan-1978: */
#define TIME_DIFF ((74 * 365 + 19) * 24 * 60 * 60)
static char g_conv_table[128] = {
'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü', 'á',
'à', 'â', 'ä', 'ã', 'å', 'ç', 'é', 'è',
'ê', 'ë', 'í', 'ì', 'î', 'ï', 'ñ', 'ó',
'ò', 'ô', 'ö', 'õ', 'ú', 'ù', 'û', 'ü',
'_', '°', '¢', '£', '§', '·', '¶', 'ß',
'®', '©', '_', '´', '¨', '_', 'Æ', 'Ø',
'_', '±', '_', '_', '¥', 'µ', 'ð', '_',
'_', '_', '_', 'ª', 'º', '_', 'æ', 'ø',
'¿', '¡', '¬', '_', '_', '_', '_', '«',
'»', '_', ' ', 'À', 'Ã', 'Õ', '_', '_',
'', '-', '\"', '\"', '`', '´', '÷', '_',
'ÿ', '_', '/', '¤', '_', '_', '_', '_',
'_', '.', '¸', '_', '_', 'Â', 'Ê', 'Á',
'Ë', 'È', 'Í', 'Î', 'Ï', 'Ì', 'Ó', 'Ô',
'_', 'Ò', 'Ú', 'Û', 'Ù', '_', '^', '~',
'', '_', '·', '°', '_', '\"', '.', '_'
};
void Convert_Mac_Characters (char *p_buf, int p_buf_len)
{
unsigned char *cp = (unsigned char *) p_buf;
int i;
for (i=0; i<p_buf_len; i++, cp++)
if (*cp >= 128)
*cp = g_conv_table[*cp-128];
else if (*cp == ':')
*cp = '.';
else if (*cp == '/')
*cp = '-';
else if (*cp < ' ')
*cp = '_';
}
void Cat_Extension(UBYTE *name,UBYTE *ext)
{
/* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
name[30 - strlen(ext)] = 0;
strcat(name,ext);
}
t_uchar *Read_Block (CDROM *p_cdrom, t_ulong p_block)
{
if (!Read_Sector (p_cdrom, p_block >> 2))
return NULL;
return p_cdrom->buffer + ((p_block & 3) << 9);
}
t_uchar *Read_Contiguous_Blocks (CDROM *p_cdrom, t_ulong p_block,
t_ulong p_last_block)
{
if (!Read_Contiguous_Sectors (p_cdrom, p_block >> 2, p_last_block >> 2))
return NULL;
return p_cdrom->buffer + ((p_block & 3) << 9);
}
/* Convert allocation block number into 512 byte block number.
*/
t_ulong AB_to_Block (VOLUME *p_volume, t_ulong p_alloc_block)
{
return p_alloc_block * (VOL(p_volume,mdb).AlBlkSiz >> 9) +
VOL(p_volume,mdb).AlBlSt + VOL(p_volume,start_block);
}
int HFS_Find_Master_Directory_Block (CDROM *p_cd, t_mdb *p_mdb)
{
t_uchar *block;
typedef struct partition_map {
t_ushort pmSig;
t_ushort reSigPad;
t_ulong pmMapBlkCnt;
t_ulong pmPyPartStart;
t_ulong pmPartBlkCnt;
char pmPartName[32];
char pmPartType[32];
} t_partition_map;
int i, entries;
int result = 2;
block = Read_Block (p_cd, 1);
if (block && block[0] == 'P' && block[1] == 'M')
{
entries = ((t_partition_map *) block)->pmMapBlkCnt;
for (i=0; i<entries; i++)
{
block = Read_Block (p_cd, i+1);
if (block && block[0] == 'P' || block[1] == 'M')
{
if (memcmp (((t_partition_map *) block)->pmPartType,
"Apple_HFS", 9) == 0)
{
result = ((t_partition_map *) block)->pmPyPartStart + 2;
break;
}
}
}
}
/* don't try to read the other block if the previous read failed */
if (block && (block = Read_Block(p_cd, result)) &&
block[0] == 'B' && block[1] == 'D')
{
memcpy (p_mdb, block, sizeof (*p_mdb));
return result;
}
else return -1;
}
t_bool Uses_HFS_Protocol (CDROM *p_cd, int *p_skip)
{
t_mdb mdb;
int blk;
SetIoErr(ERROR_NOT_A_DOS_DISK); /* initialize error code (Read_Sector() */
/* will change it if needed) */
blk = HFS_Find_Master_Directory_Block (p_cd, &mdb);
if (blk == -1)
return FALSE;
*p_skip = blk - 2; /* *p_skip holds the start block of the volume */
return TRUE;
}
t_bool HFS_Get_Header_Node (CDROM *p_cd, t_ulong p_mdb_pos,
t_mdb *p_mdb, t_hdr_node *p_hdr_node)
{
t_ulong pos = (p_mdb_pos - 2 + p_mdb->AlBlSt +
p_mdb->CTExtRec[0].StABN * (p_mdb->AlBlkSiz >> 9));
t_hdr_node *hdr;
hdr = (t_hdr_node *) Read_Block (p_cd, pos);
if (!hdr)
return FALSE;
memcpy (p_hdr_node, hdr, sizeof (t_hdr_node));
return TRUE;
}
t_node_descr *HFS_Get_Node (CDROM *p_cd, t_ulong p_mdb_pos, t_mdb *p_mdb,
t_ulong p_node)
{
t_ulong first_node;
t_ulong pos;
t_ulong max = 0;
t_ulong sub = 0;
int i;
for (i=0; i<3; i++) {
max += p_mdb->CTExtRec[i].NumABlks * (p_mdb->AlBlkSiz >> 9);
if (p_node < max)
break;
sub = max;
}
if (i==3)
return NULL;
first_node = (p_mdb_pos - 2 + p_mdb->AlBlSt +
p_mdb->CTExtRec[i].StABN * (p_mdb->AlBlkSiz >> 9));
pos = first_node + (p_node - sub);
return (t_node_descr *)Read_Block(p_cd, pos);
}
t_node_descr *HFS_Node (VOLUME *p_volume, t_ulong p_node)
{
return HFS_Get_Node (p_volume->cd, VOL(p_volume,start_block) + 2,
&VOL(p_volume,mdb), p_node);
}
void HFS_Load_Catalog_Record (VOLUME *p_volume,t_catalog_record *p_cat_rec,
char *p_node, int p_record)
{
short *sp = (short *) p_node;
int len;
int start;
start = sp[255-p_record];
start += p_node[start] + 1;
if (start & 1) start++;
len = sp[254-p_record] - start;
memcpy (p_cat_rec, p_node + start, len);
if (p_cat_rec->d.type == 3)
{
/* /// there are other fields containing names, but they don't seem to be used??? */
/* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
if (p_cat_rec->dt.CNameLen > 30) p_cat_rec->dt.CNameLen = 30;
/* convert mac characters into Amiga characters */
Convert_Mac_Characters(p_cat_rec->dt.CName,p_cat_rec->dt.CNameLen);
}
}
void HFS_Load_Leaf_Record (VOLUME *p_volume,t_leaf_record *p_leaf_rec,
char *p_node, int p_pos)
{
memcpy(p_leaf_rec,p_node + p_pos,p_node[p_pos] + 1);
/* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
if (p_leaf_rec->name_length > 30) p_leaf_rec->name_length = 30;
/* convert mac characters into Amiga characters */
Convert_Mac_Characters(p_leaf_rec->name,p_leaf_rec->name_length);
}
t_bool HFS_Find_Next_Leaf (VOLUME *p_volume, t_leaf_record_pos *p_leaf)
{
t_node_descr *node;
short *sp;
int pos;
node = HFS_Node (p_volume, p_leaf->node);
if (!node)
return FALSE;
p_leaf->record++;
if (p_leaf->record == node->NRecs) {
if (node->FLink) {
node = HFS_Node (p_volume, p_leaf->node = node->FLink);
if (!node)
return FALSE;
p_leaf->record = 0;
} else
{
SetIoErr(ERROR_NO_MORE_ENTRIES);
return FALSE;
}
}
sp = (short *) node;
pos = sp[255-p_leaf->record];
memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
HFS_Load_Leaf_Record(p_volume,&p_leaf->leaf_rec,(char *)node,pos);
HFS_Load_Catalog_Record(p_volume,&p_leaf->cat_rec, (char *) node, p_leaf->record);
return TRUE;
}
/* Find leaf record p_leaf->record in node p_leaf->node.
* Store the result in *p_leaf.
*/
t_bool HFS_Find_This_Leaf (VOLUME *p_volume, t_leaf_record_pos *p_leaf)
{
t_node_descr *node;
short *sp;
int pos;
node = HFS_Node (p_volume, p_leaf->node);
if (!node)
return FALSE;
sp = (short *) node;
pos = sp[255-p_leaf->record];
memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
HFS_Load_Leaf_Record(p_volume,&p_leaf->leaf_rec,(char *)node,pos);
HFS_Load_Catalog_Record (p_volume,&p_leaf->cat_rec, (char *) node, p_leaf->record);
return TRUE;
}
/* Find the first leaf record with parent ID p_parent_id.
* If the leaf node is found, TRUE is returned and *p_cat_rec will be
* loaded with the catalog record. Otherwise, FALSE is returned.
*/
t_bool HFS_Find_Leaf_Record (VOLUME *p_volume, t_leaf_record_pos *p_leaf,
t_ulong p_parent_id)
{
t_node_descr *node;
short *sp;
int i;
t_ulong this_node = VOL(p_volume,root_node);
t_ulong next_node;
node = HFS_Node (p_volume, VOL(p_volume,root_node));
if (!node) {
return FALSE;
}
for (;;) {
if (node->Type == 0) { /* index node */
sp = (short *) node;
next_node = (t_ulong)-1;
for (i=0; i<node->NRecs; i++) {
t_idx_record *idx = (t_idx_record *) ((char *) node + sp[255-i]);
if (idx->length != 0) {
if (idx->parent_id >= p_parent_id)
break;
next_node = idx->pointer;
}
}
} else if (node->Type == 0xff) { /* leaf node */
break;
} else {
SetIoErr(ISOERR_INTERNAL);
return FALSE;
}
if (next_node == -1) {
SetIoErr(ISOERR_INTERNAL);
return FALSE;
}
node = HFS_Node (p_volume, next_node);
if (!node) {
return FALSE;
}
this_node = next_node;
}
p_leaf->node = this_node;
p_leaf->record = 0;
memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
HFS_Load_Leaf_Record(p_volume,&p_leaf->leaf_rec,(char *)node,0xe);
HFS_Load_Catalog_Record (p_volume,&p_leaf->cat_rec, (char *) node, 0);
/* walk forwards until the same key is found: */
for (;;) {
if (p_leaf->leaf_rec.parent_id == p_parent_id)
return TRUE;
if (p_leaf->leaf_rec.parent_id > p_parent_id) {
SetIoErr(ISOERR_INTERNAL);
return FALSE;
}
if (!HFS_Find_Next_Leaf (p_volume, p_leaf)) {
SetIoErr(ISOERR_INTERNAL);
return FALSE;
}
}
}
t_bool HFS_Init_Vol_Info (VOLUME *p_volume, int p_start_block)
{
extern t_handler g_hfs_handler;
t_uchar *block;
t_hdr_node hdr;
/*
* Volume info initialization:
*/
p_volume->handler = &g_hfs_handler;
p_volume->vol_info = AllocMem (sizeof (t_hfs_vol_info), MEMF_PUBLIC);
if (!p_volume->vol_info) {
SetIoErr(ERROR_NO_FREE_STORE);
return FALSE;
}
VOL(p_volume,start_block) = p_start_block;
if (!(block = Read_Block (p_volume->cd, p_start_block + 2))) {
FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
return FALSE;
}
memcpy (&VOL(p_volume,mdb), block, sizeof (t_mdb));
if (!HFS_Get_Header_Node (p_volume->cd, p_start_block + 2,
&VOL(p_volume,mdb), &hdr)) {
FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
return FALSE;
}
VOL(p_volume,root_node) = hdr.Root;
return TRUE;
}
void HFS_Close_Vol_Info (VOLUME *p_volume)
{
FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
}
CDROM_OBJ *HFS_Alloc_Obj (void)
{
CDROM_OBJ *obj;
if (obj = AllocMem(sizeof(CDROM_OBJ),MEMF_PUBLIC | MEMF_CLEAR))
{
if (obj->obj_info = AllocMem(sizeof(t_hfs_obj_info),MEMF_PUBLIC | MEMF_CLEAR))
return(obj);
FreeMem(obj,sizeof(CDROM_OBJ));
}
SetIoErr(ERROR_NO_FREE_STORE);
return(NULL);
}
CDROM_OBJ *HFS_Open_Top_Level_Directory (VOLUME *p_volume)
{
CDROM_OBJ *obj = HFS_Alloc_Obj ();
if (!obj)
return NULL;
obj->directory_f = TRUE;
obj->handler = p_volume->handler;
OBJ(obj,parent_id) = 1;
strcpy (OBJ(obj,name), ":");
OBJ(obj,cat_rec).d.DirID = 2;
return obj;
}
CDROM_OBJ *HFS_Open_Object (VOLUME *p_volume, char *p_name, t_ulong p_parent)
{
t_leaf_record_pos leaf;
CDROM_OBJ *obj;
char name[50];
char type;
t_bool data_fork;
if (!HFS_Find_Leaf_Record (p_volume, &leaf, p_parent))
return NULL;
for (;;) {
type = leaf.cat_rec.d.type;
if (type == 1 || type == 2) {
if (leaf.leaf_rec.parent_id != p_parent) {
SetIoErr(ISOERR_NOT_FOUND);
return NULL;
}
memcpy (name, leaf.leaf_rec.name, leaf.leaf_rec.name_length);
name[leaf.leaf_rec.name_length] = 0;
if (type == 1) {
if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0)
break;
} else {
if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0) {
data_fork = TRUE;
break;
}
Cat_Extension(name,"²");
if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0) {
data_fork = FALSE;
break;
}
}
}
if (!HFS_Find_Next_Leaf (p_volume, &leaf))
return NULL;
}
obj = HFS_Alloc_Obj ();
obj->directory_f = (type == 1);
obj->handler = p_volume->handler;
OBJ(obj,data_fork) = data_fork;
OBJ(obj,parent_id) = p_parent;
strcpy (OBJ(obj,name), name);
memcpy (&OBJ(obj,cat_rec), &leaf.cat_rec, sizeof (t_catalog_record));
return obj;
}
/* Open the object with name p_name in the directory p_dir.
* p_name must not contain '/' or ':' characters.
*/
CDROM_OBJ *HFS_Open_Obj_In_Directory (VOLUME *p_volume,CDROM_OBJ *p_dir, char *p_name)
{
return HFS_Open_Object (p_volume, p_name, OBJ(p_dir,cat_rec).d.DirID);
}
CDROM_OBJ *HFS_Find_Parent (VOLUME *p_volume,CDROM_OBJ *p_obj)
{
t_leaf_record_pos leaf;
if (OBJ(p_obj,parent_id) == 2)
return HFS_Open_Top_Level_Directory (p_volume);
if (!HFS_Find_Leaf_Record (p_volume, &leaf, OBJ(p_obj,parent_id)))
return NULL;
for (;;) {
if (leaf.leaf_rec.parent_id != OBJ(p_obj,parent_id)) {
SetIoErr(ISOERR_INTERNAL);
return NULL;
}
if (leaf.cat_rec.d.type == 3) {
char buf[50];
memcpy (buf, leaf.cat_rec.dt.CName, leaf.cat_rec.dt.CNameLen);
buf[leaf.cat_rec.dt.CNameLen] = 0;
return HFS_Open_Object (p_volume, buf, leaf.cat_rec.dt.ParID);
}
if (!HFS_Find_Next_Leaf (p_volume, &leaf))
return NULL;
}
}
void HFS_Close_Obj (CDROM_OBJ *p_obj)
{
FreeMem (p_obj->obj_info, sizeof (t_hfs_obj_info));
FreeMem (p_obj, sizeof (CDROM_OBJ));
}
int HFS_Read_From_File (VOLUME *p_volume,CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
{
unsigned long block;
int remain_block, remain_file, remain;
int len;
CDROM *cd;
int pos;
int buf_pos = 0;
int todo;
t_bool data_fork = OBJ(p_file,data_fork);
t_ulong first_block;
t_ulong last_block;
t_ulong data_length = (data_fork ? OBJ(p_file,cat_rec).f.LgLen :
OBJ(p_file,cat_rec).f.RLgLen);
if (p_file->pos == data_length)
/* at end of file: */
return 0;
cd = p_volume->cd;
first_block = AB_to_Block (p_volume,
data_fork ?
OBJ(p_file,cat_rec).f.ExtRec[0].StABN :
OBJ(p_file,cat_rec).f.RExtRec[0].StABN);
block = first_block + (p_file->pos >> 9);
last_block = first_block + ((data_length-1) >> 9);
todo = p_buffer_length;
while (todo) {
t_uchar *data;
if (!(data = Read_Contiguous_Blocks (cd, block, last_block))) {
return -1;
}
remain_block = 512 - (pos = (p_file->pos & 511));
remain_file = data_length - p_file->pos;
remain = (remain_block < remain_file) ? remain_block : remain_file;
len = (todo < remain) ? todo : remain;
CopyMem ((APTR) (data + pos), (APTR) (p_buffer + buf_pos), len);
buf_pos += len;
p_file->pos += len;
todo -= len;
if (p_file->pos >= data_length)
break;
block++;
}
return buf_pos;
}
LONG HFS_Cdrom_Info (VOLUME *p_volume,CDROM_OBJ *p_obj, CDROM_INFO *p_info)
{
p_info->symlink_f = 0;
p_info->directory_f = p_obj->directory_f;
p_info->name_length = strlen (OBJ(p_obj,name));
memcpy (p_info->name, OBJ(p_obj,name), p_info->name_length);
if (p_info->directory_f) {
p_info->file_length = 0;
p_info->date = OBJ(p_obj,cat_rec).d.CrDat - TIME_DIFF;
} else {
if (OBJ(p_obj,data_fork))
p_info->file_length = OBJ(p_obj,cat_rec).f.LgLen;
else
p_info->file_length = OBJ(p_obj,cat_rec).f.RLgLen;
p_info->date = OBJ(p_obj,cat_rec).f.CrDat - TIME_DIFF;
}
return(0);
}
/* The 'offset' is a long integer coded like this:
*
* Bit: | 31 ... 8 | 7 6 | 5 4 3 2 1 0
* | | |
* Contents: | Node number | Fork | Record number
*
* The "Fork" value is encoded as follows:
*
* 0 - data fork
* 1 - resource fork
* 2 - directory
* 3 - illegal
*/
LONG HFS_Examine_Next (VOLUME *p_volume,CDROM_OBJ *p_obj, CDROM_INFO *p_info,
unsigned long *p_offset)
{
t_leaf_record_pos leaf;
short fork = 3;
while (fork == 3) {
if (*p_offset == 0) {
if (!HFS_Find_Leaf_Record (p_volume, &leaf, OBJ(p_obj,cat_rec).d.DirID))
return(IoErr());
} else {
leaf.node = *p_offset >> 8;
leaf.record = *p_offset & 63;
fork = (*p_offset & 0xC0) >> 6;
if (fork == 0) {
if (!HFS_Find_This_Leaf (p_volume, &leaf))
return(IoErr());
} else {
if (!HFS_Find_Next_Leaf (p_volume, &leaf))
return(IoErr());
if (leaf.leaf_rec.parent_id != OBJ(p_obj,cat_rec).d.DirID)
return(ERROR_NO_MORE_ENTRIES);
}
}
if (leaf.cat_rec.d.type == 1)
fork = 2;
else if (leaf.cat_rec.d.type != 2)
fork = 3;
else if (fork != 0 && leaf.cat_rec.f.LgLen > 0)
fork = 0;
else if (leaf.cat_rec.f.RLgLen > 0)
fork = 1;
else
fork = 3;
*p_offset = ((leaf.node << 8) + (fork << 6) + leaf.record);
}
p_info->symlink_f = 0;
p_info->directory_f = (leaf.cat_rec.d.type == 1);
memcpy(p_info->name,leaf.leaf_rec.name,leaf.leaf_rec.name_length);
p_info->name[leaf.leaf_rec.name_length] = 0;
if (p_info->directory_f)
{
p_info->file_length = 0;
p_info->date = leaf.cat_rec.d.CrDat - TIME_DIFF;
}
else
{
if (fork == 0)
{
p_info->file_length = leaf.cat_rec.f.LgLen;
}
else
{
Cat_Extension(p_info->name,"²");
p_info->file_length = leaf.cat_rec.f.RLgLen;
}
p_info->date = leaf.cat_rec.f.CrDat - TIME_DIFF;
}
p_info->name_length = strlen(p_info->name);
p_info->suppl_info = NULL;
return(0);
}
void *HFS_Clone_Obj_Info (void *p_info)
{
t_hfs_obj_info *info = (t_hfs_obj_info *) p_info;
t_hfs_obj_info *new;
new = AllocMem (sizeof (t_hfs_obj_info), MEMF_PUBLIC);
if (!new)
return NULL;
memcpy (new, info, sizeof (t_hfs_obj_info));
return new;
}
t_bool HFS_Is_Top_Level_Obj (VOLUME *p_volume,CDROM_OBJ *p_obj)
{
return OBJ(p_obj,parent_id) == 1;
}
t_bool HFS_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
{
if (OBJ(p_obj1,cat_rec).d.type != OBJ(p_obj2,cat_rec).d.type)
return FALSE;
if (OBJ(p_obj1,cat_rec).d.type == 1)
return OBJ(p_obj1,cat_rec).d.DirID == OBJ(p_obj2,cat_rec).d.DirID;
else
return OBJ(p_obj1,cat_rec).f.FlNum == OBJ(p_obj2,cat_rec).f.FlNum;
}
t_ulong HFS_Creation_Date (VOLUME *p_volume)
{
return VOL(p_volume,mdb).CrDate - TIME_DIFF;
}
/* Return volume size in 2048 byte blocks:
*/
t_ulong HFS_Volume_Size (VOLUME *p_volume)
{
return(VOL(p_volume,mdb).NmAlBlks * (VOL(p_volume,mdb).AlBlkSiz >> 9)
+ VOL(p_volume,mdb).AlBlSt + 2);
}
/* Return number of free blocks */
t_ulong HFS_Volume_Free (VOLUME *p_volume)
{
return(VOL(p_volume,mdb).FreeBks * (VOL(p_volume,mdb).AlBlkSiz >> 9)
+ VOL(p_volume,mdb).AlBlSt + 2);
}
t_ulong HFS_Block_Size (VOLUME *p_volume)
{
return 512;
}
void HFS_Volume_Id (VOLUME *p_volume, char *p_buf, int p_buf_length)
{
int len = p_buf_length - 1;
if (len > VOL(p_volume,mdb).VolNameLen)
len = VOL(p_volume,mdb).VolNameLen;
memcpy (p_buf, VOL(p_volume,mdb).VolName, len);
p_buf[len] = 0;
Convert_Mac_Characters (p_buf, len);
}
t_ulong HFS_Location (VOLUME *p_volume,CDROM_OBJ *p_obj)
{
if (p_obj->directory_f) {
if (Is_Top_Level_Object (p_volume,p_obj))
return FALSE;
return OBJ(p_obj,cat_rec).d.DirID;
} else
return OBJ(p_obj,cat_rec).f.FlNum;
}
t_ulong HFS_File_Length (CDROM_OBJ *p_obj)
{
return (OBJ(p_obj,data_fork) ?
OBJ(p_obj,cat_rec).f.LgLen :
OBJ(p_obj,cat_rec).f.RLgLen);
}
t_handler g_hfs_handler = {
HFS_Close_Vol_Info,
HFS_Open_Top_Level_Directory,
HFS_Open_Obj_In_Directory,
HFS_Find_Parent,
HFS_Close_Obj,
HFS_Read_From_File,
HFS_Cdrom_Info,
HFS_Examine_Next,
HFS_Clone_Obj_Info,
HFS_Is_Top_Level_Obj,
HFS_Same_Objects,
HFS_Creation_Date,
HFS_Volume_Size,
HFS_Volume_Free,
HFS_Volume_Id,
HFS_Location,
HFS_File_Length,
HFS_Block_Size
};