HFS+ enhancement by Vladimir Serbinenko:

Mostly symlinks, POSIX files and attributes.
This commit is contained in:
Thomas Schmitt 2012-05-25 08:25:45 +02:00
parent 45bf3d9717
commit ed986aa4ea
2 changed files with 171 additions and 36 deletions

View File

@ -107,9 +107,22 @@ int set_hfsplus_name(Ecma119Image *t, char *name, HFSPlusNode *node)
for (iptr = ucs_name, optr = node->name; *iptr; iptr++) for (iptr = ucs_name, optr = node->name; *iptr; iptr++)
{ {
const uint16_t *dptr; const uint16_t *dptr;
uint8_t high = ((uint8_t *) iptr)[0]; uint16_t val = ntohs (*iptr);
uint8_t low = ((uint8_t *) iptr)[1]; uint8_t high = val >> 8;
/* FIXME: decompose jamos. */ uint8_t low = val & 0xff;
if (val >= 0xac00 && val <= 0xd7a3)
{
uint16_t s, l, v, t;
s = val - 0xac00;
l = s / (21 * 28);
v = (s % (21 * 28)) / 28;
t = s % 28;
*optr++ = htons (l + 0x1100);
*optr++ = htons (v + 0x1161);
if (t)
*optr++ = htons (t + 0x11a7);
continue;
}
if (!hfsplus_decompose_pages[high]) if (!hfsplus_decompose_pages[high])
{ {
*optr++ = *iptr; *optr++ = *iptr;
@ -170,6 +183,8 @@ int set_hfsplus_name(Ecma119Image *t, char *name, HFSPlusNode *node)
} }
*optr = 0; *optr = 0;
free (ucs_name);
node->strlen = ucslen (node->name); node->strlen = ucslen (node->name);
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -188,6 +203,7 @@ int hfsplus_count_tree(Ecma119Image *t, IsoNode *iso)
switch (iso->type) { switch (iso->type) {
case LIBISO_SYMLINK: case LIBISO_SYMLINK:
case LIBISO_SPECIAL:
case LIBISO_FILE: case LIBISO_FILE:
t->hfsp_nfiles++; t->hfsp_nfiles++;
return ISO_SUCCESS; return ISO_SUCCESS;
@ -210,8 +226,6 @@ int hfsplus_count_tree(Ecma119Image *t, IsoNode *iso)
return ISO_SUCCESS; return ISO_SUCCESS;
case LIBISO_BOOT: case LIBISO_BOOT:
return ISO_SUCCESS; return ISO_SUCCESS;
case LIBISO_SPECIAL:
return ISO_SUCCESS;
default: default:
/* should never happen */ /* should never happen */
return ISO_ASSERT_FAILURE; return ISO_ASSERT_FAILURE;
@ -239,7 +253,8 @@ int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
return 0; return 0;
} }
if (iso->type == LIBISO_FILE && iso->type == LIBISO_DIR) if (iso->type != LIBISO_FILE && iso->type != LIBISO_DIR
&& iso->type != LIBISO_SYMLINK && iso->type != LIBISO_SPECIAL)
return 0; return 0;
cat_id = t->hfsp_cat_id++; cat_id = t->hfsp_cat_id++;
@ -248,8 +263,26 @@ int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
t->hfsp_leafs[t->hfsp_curleaf].node = iso; t->hfsp_leafs[t->hfsp_curleaf].node = iso;
t->hfsp_leafs[t->hfsp_curleaf].cat_id = cat_id; t->hfsp_leafs[t->hfsp_curleaf].cat_id = cat_id;
t->hfsp_leafs[t->hfsp_curleaf].parent_id = parent_id; t->hfsp_leafs[t->hfsp_curleaf].parent_id = parent_id;
t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_NONE;
if (iso->type == LIBISO_FILE) switch (iso->type)
{
case LIBISO_SYMLINK:
{
IsoSymlink *sym = (IsoSymlink*) iso;
t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
t->hfsp_leafs[t->hfsp_curleaf].symlink_size = strlen (sym->dest);
t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_SYMLINK;
t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
break;
}
case LIBISO_SPECIAL:
t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_SPECIAL;
t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
break;
case LIBISO_FILE:
{ {
IsoFile *file = (IsoFile*) iso; IsoFile *file = (IsoFile*) iso;
t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE; t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_FILE;
@ -259,10 +292,15 @@ int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
} }
t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata); t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common) + 2 * sizeof (struct hfsplus_forkdata);
} }
else if (iso->type == LIBISO_DIR) break;
case LIBISO_DIR:
{ {
t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_DIR; t->hfsp_leafs[t->hfsp_curleaf].type = HFSPLUS_DIR;
t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common); t->hfsp_leafs[t->hfsp_curleaf].used_size = t->hfsp_leafs[t->hfsp_curleaf].strlen * 2 + 8 + 2 + sizeof (struct hfsplus_catfile_common);
break;
}
default:
return ISO_ASSERT_FAILURE;
} }
cleaf = t->hfsp_curleaf; cleaf = t->hfsp_curleaf;
t->hfsp_leafs[t->hfsp_curleaf].nchildren = 0; t->hfsp_leafs[t->hfsp_curleaf].nchildren = 0;
@ -277,6 +315,7 @@ int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id)
t->hfsp_leafs[t->hfsp_curleaf].file = 0; t->hfsp_leafs[t->hfsp_curleaf].file = 0;
t->hfsp_leafs[t->hfsp_curleaf].cat_id = parent_id; t->hfsp_leafs[t->hfsp_curleaf].cat_id = parent_id;
t->hfsp_leafs[t->hfsp_curleaf].parent_id = cat_id; t->hfsp_leafs[t->hfsp_curleaf].parent_id = cat_id;
t->hfsp_leafs[t->hfsp_curleaf].unix_type = UNIX_NONE;
t->hfsp_curleaf++; t->hfsp_curleaf++;
if (iso->type == LIBISO_DIR) if (iso->type == LIBISO_DIR)
@ -351,6 +390,7 @@ static
int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer) int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer)
{ {
Ecma119Image *t; Ecma119Image *t;
uint32_t i;
if (writer == NULL) { if (writer == NULL) {
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
@ -368,6 +408,14 @@ int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer)
t->hfsp_extent_file_start = t->curblock; t->hfsp_extent_file_start = t->curblock;
t->curblock++; t->curblock++;
iso_msg_debug(t->image->id, "(d) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes);
for (i = 0; i < t->hfsp_nleafs; i++)
if (t->hfsp_leafs[i].unix_type == UNIX_SYMLINK)
{
t->hfsp_leafs[i].symlink_block = t->curblock;
t->curblock += (t->hfsp_leafs[i].symlink_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE;
}
iso_msg_debug(t->image->id, "(a) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes); iso_msg_debug(t->image->id, "(a) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes);
return ISO_SUCCESS; return ISO_SUCCESS;
@ -499,9 +547,7 @@ int hfsplus_writer_write_data(IsoImageWriter *writer)
struct hfsplus_btnode *node_head; struct hfsplus_btnode *node_head;
struct hfsplus_btheader *tree_head; struct hfsplus_btheader *tree_head;
int level; int level;
uint32_t curpos = 1; uint32_t curpos = 1, i;
uint32_t src_start;
uint64_t src_size;
if (writer == NULL) { if (writer == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
@ -667,26 +713,83 @@ int hfsplus_writer_write_data(IsoImageWriter *writer)
FIXME: FIXME:
uint8_t user_flags; uint8_t user_flags;
uint8_t group_flags; uint8_t group_flags;
uint32_t special;
uint8_t finder_info[32];
*/
iso_msb ((uint8_t *) &common->flags, (t->hfsp_leafs[curnode].type == HFSPLUS_DIR) ? 0 : 2, 2); finder info
*/
if (t->hfsp_leafs[curnode].type == HFSPLUS_FILE)
{
if (t->hfsp_leafs[curnode].unix_type == UNIX_SYMLINK)
{
memcpy (common->file_type, "slnk", 4);
memcpy (common->file_creator, "rhap", 4);
}
else
{
struct iso_hfsplus_xinfo_data *xinfo;
ret = iso_node_get_xinfo(t->hfsp_leafs[curnode].node,
iso_hfsplus_xinfo_func,
(void *) &xinfo);
if (ret > 0)
{
memcpy (common->file_type, xinfo->type_code,
4);
memcpy (common->file_creator,
xinfo->creator_code, 4);
/* use xinfo */;
}
else if (ret < 0)
return ret;
else
{
memcpy (common->file_type, "????", 4);
memcpy (common->file_creator, "????", 4);
}
}
if (t->hfsp_leafs[curnode].unix_type == UNIX_SPECIAL
&& (S_ISBLK(t->hfsp_leafs[curnode].node->mode)
|| S_ISCHR(t->hfsp_leafs[curnode].node->mode)))
iso_msb ((uint8_t *) &common->special,
(((IsoSpecial*) t->hfsp_leafs[curnode].node)->dev & 0xffffffff),
4);
iso_msb ((uint8_t *) &common->flags, 2, 2);
}
else if (t->hfsp_leafs[curnode].type == HFSPLUS_DIR)
{
iso_msb ((uint8_t *) &common->flags, 0, 2);
}
curoff += sizeof (*common); curoff += sizeof (*common);
if (t->hfsp_leafs[curnode].type == HFSPLUS_FILE) if (t->hfsp_leafs[curnode].type == HFSPLUS_FILE)
{ {
uint64_t sz;
uint32_t blk;
data_fork = (struct hfsplus_forkdata *) (buffer + curoff); data_fork = (struct hfsplus_forkdata *) (buffer + curoff);
ret = filesrc_block_and_size(t, t->hfsp_leafs[curnode].file, &src_start, &src_size); if (t->hfsp_leafs[curnode].unix_type == UNIX_SYMLINK)
if (ret < 0) {
blk = t->hfsp_leafs[curnode].symlink_block;
sz = t->hfsp_leafs[curnode].symlink_size;
}
else if (t->hfsp_leafs[curnode].unix_type == UNIX_SPECIAL)
{
blk = 0;
sz = 0;
}
else
{
ret = filesrc_block_and_size(t,
t->hfsp_leafs[curnode].file,
&blk, &sz);
if (ret <= 0)
return ret; return ret;
}
iso_msb ((uint8_t *) &data_fork->size, src_size >> 32, 4); iso_msb ((uint8_t *) &data_fork->size, sz >> 32, 4);
iso_msb ((uint8_t *) &data_fork->size + 4, src_size, 4); iso_msb ((uint8_t *) &data_fork->size + 4, sz, 4);
iso_msb ((uint8_t *) &data_fork->clumpsize, HFSPLUS_BLOCK_SIZE, 4); iso_msb ((uint8_t *) &data_fork->clumpsize, HFSPLUS_BLOCK_SIZE, 4);
iso_msb ((uint8_t *) &data_fork->blocks, (src_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); iso_msb ((uint8_t *) &data_fork->blocks, (sz + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4);
iso_msb ((uint8_t *) &data_fork->extents[0].start, src_start - t->hfsp_part_start, 4); iso_msb ((uint8_t *) &data_fork->extents[0].start, blk - t->hfsp_part_start, 4);
iso_msb ((uint8_t *) &data_fork->extents[0].count, (src_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); iso_msb ((uint8_t *) &data_fork->extents[0].count, (sz + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4);
curoff += sizeof (*data_fork) * 2; curoff += sizeof (*data_fork) * 2;
/* FIXME: resource fork */ /* FIXME: resource fork */
@ -730,6 +833,24 @@ int hfsplus_writer_write_data(IsoImageWriter *writer)
if (ret < 0) if (ret < 0)
return ret; return ret;
iso_msg_debug(t->image->id, "(d) %d written", (int) t->bytes_written / 0x800);
memset (buffer, 0, sizeof (buffer));
for (i = 0; i < t->hfsp_nleafs; i++)
if (t->hfsp_leafs[i].unix_type == UNIX_SYMLINK)
{
IsoSymlink *sym = (IsoSymlink*) t->hfsp_leafs[i].node;
int overhead;
ret = iso_write(t, sym->dest, t->hfsp_leafs[i].symlink_size);
if (ret < 0)
return ret;
overhead = t->hfsp_leafs[i].symlink_size % HFSPLUS_BLOCK_SIZE;
if (overhead)
overhead = HFSPLUS_BLOCK_SIZE - overhead;
ret = iso_write(t, buffer, overhead);
if (ret < 0)
return ret;
}
iso_msg_debug(t->image->id, "(a) %d written", (int) t->bytes_written / 0x800); iso_msg_debug(t->image->id, "(a) %d written", (int) t->bytes_written / 0x800);
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -792,8 +913,14 @@ int hfsplus_writer_free_data(IsoImageWriter *writer)
for (i = 0; i < t->hfsp_curleaf; i++) for (i = 0; i < t->hfsp_curleaf; i++)
if (t->hfsp_leafs[i].type != HFSPLUS_FILE_THREAD if (t->hfsp_leafs[i].type != HFSPLUS_FILE_THREAD
&& t->hfsp_leafs[i].type != HFSPLUS_DIR_THREAD) && t->hfsp_leafs[i].type != HFSPLUS_DIR_THREAD)
{
free (t->hfsp_leafs[i].name); free (t->hfsp_leafs[i].name);
free (t->hfsp_leafs[i].cmp_name);
}
free(t->hfsp_leafs); free(t->hfsp_leafs);
for (i = 0; i < t->hfsp_nlevels; i++)
free (t->hfsp_levels[i].nodes);
free(t->hfsp_levels);
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -851,6 +978,7 @@ int hfsplus_writer_create(Ecma119Image *target)
target->hfsp_leafs[target->hfsp_curleaf].cat_id = 2; target->hfsp_leafs[target->hfsp_curleaf].cat_id = 2;
target->hfsp_leafs[target->hfsp_curleaf].parent_id = 1; target->hfsp_leafs[target->hfsp_curleaf].parent_id = 1;
target->hfsp_leafs[target->hfsp_curleaf].nchildren = 0; target->hfsp_leafs[target->hfsp_curleaf].nchildren = 0;
target->hfsp_leafs[target->hfsp_curleaf].unix_type = UNIX_NONE;
target->hfsp_curleaf++; target->hfsp_curleaf++;
target->hfsp_leafs[target->hfsp_curleaf].name = target->hfsp_leafs[target->hfsp_curleaf - 1].name; target->hfsp_leafs[target->hfsp_curleaf].name = target->hfsp_leafs[target->hfsp_curleaf - 1].name;
@ -862,6 +990,7 @@ int hfsplus_writer_create(Ecma119Image *target)
target->hfsp_leafs[target->hfsp_curleaf].file = 0; target->hfsp_leafs[target->hfsp_curleaf].file = 0;
target->hfsp_leafs[target->hfsp_curleaf].cat_id = 1; target->hfsp_leafs[target->hfsp_curleaf].cat_id = 1;
target->hfsp_leafs[target->hfsp_curleaf].parent_id = 2; target->hfsp_leafs[target->hfsp_curleaf].parent_id = 2;
target->hfsp_leafs[target->hfsp_curleaf].unix_type = UNIX_NONE;
target->hfsp_curleaf++; target->hfsp_curleaf++;
dir = (IsoDir*)target->image->root; dir = (IsoDir*)target->image->root;

View File

@ -48,6 +48,10 @@ struct hfsplus_node
IsoNode *node; /*< reference to the iso node */ IsoNode *node; /*< reference to the iso node */
enum { UNIX_NONE, UNIX_SYMLINK, UNIX_SPECIAL } unix_type;
uint32_t symlink_block;
uint32_t symlink_size;
enum hfsplus_node_type type; enum hfsplus_node_type type;
IsoFileSrc *file; IsoFileSrc *file;
uint32_t cat_id; uint32_t cat_id;
@ -168,7 +172,9 @@ struct hfsplus_catfile_common
uint8_t group_flags; uint8_t group_flags;
uint16_t mode; uint16_t mode;
uint32_t special; uint32_t special;
uint8_t finder_info[32]; uint8_t file_type[4]; /* For folders: window size */
uint8_t file_creator[4]; /* For folders: window size */
uint8_t finder_info[24];
uint32_t text_encoding; uint32_t text_encoding;
uint32_t reserved; uint32_t reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));