Introduced inner API iso_apm_partition_request for definition of

Apple Partition Map entries by hfsplus.c.
This commit is contained in:
Thomas Schmitt 2012-05-26 23:04:42 +02:00
parent 6fc6a09040
commit 8770148cad
6 changed files with 300 additions and 1 deletions

View File

@ -122,6 +122,9 @@ void ecma119_image_free(Ecma119Image *t)
for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
if (t->hfsplus_blessed[i] != NULL)
iso_node_unref(t->hfsplus_blessed[i]);
for (i = 0; (int) i < t->apm_req_count; i++)
if (t->apm_req[i] != NULL)
free(t->apm_req[i]);
free(t);
}
@ -1876,6 +1879,13 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
if (target->hfsplus_blessed[i] != NULL)
iso_node_ref(target->hfsplus_blessed[i]);
}
target->apm_block_size = 512;
for (i = 0; i < ISO_APM_ENTRIES_MAX; i++)
target->apm_req[i] = NULL;
/* Set apm_block_size to 2048, if desired, before pthread_create()
at the end of this function.
Register any Apple Partition Map entries before pthread_create().
*/
/*
* 2. Based on those options, create needed writers: iso, joliet...

View File

@ -70,6 +70,11 @@
#endif
/* The maximum number of Apple Partition Map entries.
*/
#define ISO_APM_ENTRIES_MAX 63
/**
* Holds the options for the image generation.
*/
@ -598,6 +603,7 @@ struct ecma119_image
/*
* HFS+ related information
* (by Vladimir Serbinenko, see libisofs/hfsplus.c)
*/
HFSPlusNode *hfsp_leafs;
struct hfsplus_btree_level *hfsp_levels;
@ -776,7 +782,17 @@ struct ecma119_image
char ascii_disc_label[ISO_DISC_LABEL_SIZE];
/* See IsoImage and libisofs.h */
IsoNode *hfsplus_blessed[ISO_HFSPLUS_BLESS_MAX];
/* Apple Partition Map description. To be composed during IsoImageWriter
method ->compute_data_blocks() by calling iso_register_apm_entry().
*/
struct iso_apm_partition_request *apm_req[ISO_APM_ENTRIES_MAX];
int apm_req_count;
/* 512 by default. May be changed to 2048 before writer thread starts. */
int apm_block_size;
};
#define BP(a,b) [(b) - (a) + 1]

View File

@ -7154,6 +7154,9 @@ int iso_image_hfsplus_bless(IsoImage *img, enum IsoHfsplusBlessings blessing,
(FAILURE, HIGH, -378) */
#define ISO_SECT_SCATTERED 0xE830FE82
/** Too many Apple Partition Map entries requested (FAILURE, HIGH, -377)*/
#define ISO_BOOT_TOO_MANY_APM 0xE830FE81
/* Internal developer note:

View File

@ -474,6 +474,8 @@ const char *iso_error_to_msg(int errcode)
return "ACL text contains multiple entries of user::, group::, other::";
case ISO_SECT_SCATTERED:
return "File sections do not form consecutive array of blocks";
case ISO_BOOT_TOO_MANY_APM:
return "Too many Apple Partition Map entries requested";
default:
return "Unknown error";
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2008 Vreixo Formoso
* Copyright (c) 2010 - 2011 Thomas Schmitt
* Copyright (c) 2010 - 2012 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
@ -688,6 +688,189 @@ static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag)
}
/* Convenience frontend for iso_register_apm_entry().
name and type are 0-terminated strings.
*/
int iso_quick_apm_entry(Ecma119Image *t,
uint32_t start_block, uint32_t block_count, char *name, char *type)
{
int ret;
struct iso_apm_partition_request *entry;
entry = calloc(1, sizeof(struct iso_apm_partition_request));
if (entry == NULL)
return ISO_OUT_OF_MEM;
entry->start_block = start_block;
entry->block_count = block_count;
strncpy((char *) entry->name, name, 32);
strncpy((char *) entry->type, type, 32);
ret = iso_register_apm_entry(t, entry, 0);
free(entry);
return ret;
}
/**
* Compare the start_sectors of two iso_apm_partition_request
*/
static
int cmp_apm_partition_request(const void *f1, const void *f2)
{
struct iso_apm_partition_request *r1, *r2;
r1 = *((struct iso_apm_partition_request **) f1);
r2 = *((struct iso_apm_partition_request **) f2);
if (r1->start_block < r2->start_block)
return -1;
if (r1->start_block > r2->start_block)
return 1;
return 0;
}
static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size,
struct iso_apm_partition_request *req,
uint8_t *buf, int map_entries, int flag)
{
uint8_t *wpt;
int block_fac;
block_fac = apm_block_size / 512;
memset(buf, apm_block_size, 0);
wpt = buf;
/* Signature */
wpt[0] = 'P'; wpt[1] = 'M';
wpt+= 2;
/* reserved */
wpt += 2;
/* Number of partition entries */
iso_msb(wpt, (uint32_t) map_entries, 4);
wpt += 4;
/* Physical block start of partition */
iso_msb(wpt, req->start_block * block_fac, 4);
wpt += 4;
/* Physical block count of partition */
iso_msb(wpt, req->block_count * block_fac, 4);
wpt += 4;
/* Partition name */
memcpy(wpt, req->name, 32);
wpt += 32;
/* Type string */
memcpy(wpt, req->type, 32);
wpt += 32;
/* Logical block start */
iso_msb(wpt, 0, 4);
wpt += 4;
/* Logical block count */
iso_msb(wpt, req->block_count * block_fac, 4);
wpt += 4;
/* Status flags : bit0= entry is valid , bit1= entry is allocated */
iso_msb(wpt, 3, 4);
wpt += 4;
/* boot_block , boot_bytes , processor , reserved : are all 0 */
return ISO_SUCCESS;
}
static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
{
int i, ret, gap_counter = 0, up_to;
uint32_t part_end, goal;
char gap_name[33];
#ifdef NIX
/* Disabled */
/* <<< ts B20526 : Dummy mock-up */
if (t->apm_req_count <= 0) {
/*
ret = iso_quick_apm_entry(t, 16, 20, "Test1_name_16_20", "Test1_type");
*/
ret = iso_quick_apm_entry(t, 30, 20, "Test1_name_30_20", "Test1_type");
if (ret < 0)
return ret;
ret = iso_quick_apm_entry(t, 100, 400, "Test2_name_100_400",
"Test2_type");
if (ret < 0)
return ret;
}
#endif /* NIX */
if (t->apm_req_count <= 0)
return 2;
/* Find out whether an entry with start_block == 1 is requested */
for (i = 0; i < t->apm_req_count; i++) {
if (t->apm_req[i]->start_block <= 1)
break;
}
if (i >= t->apm_req_count) {
ret = iso_quick_apm_entry(t, 1, 0, "Apple", "Apple_partition_map");
if (ret < 0)
return ret;
}
/* Sort and fill gaps */
qsort(t->apm_req, t->apm_req_count,
sizeof(struct iso_apm_partition_request *), cmp_apm_partition_request);
/* t->apm_req_count will grow during the loop */
up_to = t->apm_req_count + 1;
for (i = 1; i < up_to; i++) {
if (i < up_to - 1)
goal = t->apm_req[i]->start_block;
else
goal = img_blocks;
if (i == 1) {
/* Description of APM itself */
/* Actual APM size is not yet known. Protection begins at PVD */
part_end = 16;
if (goal < 16 && goal> 1)
part_end = goal;
} else {
part_end = t->apm_req[i - 1]->start_block +
t->apm_req[i - 1]->block_count;
}
if (part_end > goal) {
/* >>> Overlapping partition. ??? Warn ??? Bail out ??? */;
}
if (part_end < goal) {
sprintf(gap_name, "Gap%d", gap_counter);
gap_counter++;
ret = iso_quick_apm_entry(t, part_end,
goal - part_end,
gap_name, "ISO9660_data");
if (ret < 0)
return ret;
}
}
/* Merge list of gap partitions with list of already sorted entries */
qsort(t->apm_req, t->apm_req_count,
sizeof(struct iso_apm_partition_request *), cmp_apm_partition_request);
/* If block size is larger than 512, then not all 63 entries will fit */
if ((t->apm_req_count + 1) * t->apm_block_size > 32768)
return ISO_BOOT_TOO_MANY_APM;
t->apm_req[0]->start_block = 1;
/* >>> ts B20526 : ??? isohybrid has 16. Logical block count is 10. Why ?*/
t->apm_req[0]->block_count = t->apm_req_count;
for (i = 0; i < t->apm_req_count; i++) {
ret = iso_write_apm_entry(t, t->apm_block_size, t->apm_req[i],
buf + (i + 1) * t->apm_block_size, t->apm_req_count, 0);
if (ret < 0)
return ret;
}
return ISO_SUCCESS;
}
int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
{
int ret, int_img_blocks, sa_type, i, will_append = 0;
@ -735,6 +918,32 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
}
return ISO_SUCCESS;
}
/* If APM entries were submitted to iso_register_apm_entry(), then they
get sprinkled over the system area before any other data get inserted.
Note that Block0 of the APM is not written but is in the responsibility
of the MBR template. Its block size MUST match t->apm_block_size.
>>> ts B20526
>>> ??? Shall i check t->system_area_data whether there are the first
>>> ??? four bytes of a Block0 and what block size they announce ?
>>> pro: That would prevent cruel mishaps
>>> con: t->system_area_data is totally opaque up to now.
>>> I cannot easily predict whether the first bytes get altered
>>> in the course of processing.
>>> ts B20526
>>> This does not care for eventual image enlargements in last minute.
>>> A sa_type, that does this, will have to adjust the last APM entry
>>> if exactness matters.
*/
ret = iso_write_apm(t, img_blocks, buf);
if (ret < 0) {
iso_msg_submit(t->image->id, ret, 0,
"Cannot set up Apple Partition Map");
return ret;
}
if (sa_type == 0 && (t->system_area_options & 1)) {
/* Write GRUB protective msdos label, i.e. a simple partition table */
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
@ -942,3 +1151,22 @@ ex:;
LIBISO_FREE_MEM(msg);
return ret;
}
int iso_register_apm_entry(Ecma119Image *t,
struct iso_apm_partition_request *req, int flag)
{
struct iso_apm_partition_request *entry;
if (t->apm_req_count >= ISO_APM_ENTRIES_MAX)
return ISO_BOOT_TOO_MANY_APM;
entry = calloc(1, sizeof(struct iso_apm_partition_request));
if (entry == NULL)
return ISO_OUT_OF_MEM;
memcpy(entry, req, sizeof(struct iso_apm_partition_request));
t->apm_req[t->apm_req_count] = entry;
t->apm_req_count++;
return ISO_SUCCESS;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008 Vreixo Formoso
* Copyright (c) 2012 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
@ -63,4 +64,43 @@ int iso_read_mipsel_elf(Ecma119Image *t, int flag);
*/
int iso_compute_append_partitions(Ecma119Image *t, int flag);
/* The parameter struct for production of a single Apple Partition Map entry.
See also the partial APM description in doc/boot_sectors.txt.
The list of entries is stored in Ecma119Image.apm_req.
The size of a block can be chosen by setting Ecma119Image.apm_block_size.
If an entry has start_block <=1, then its block_count will be adjusted
to the final size of the partition map.
If no such entry is requested, then it will be prepended automatically
with name "Apple" and type "Apple_partition_map".
*/
struct iso_apm_partition_request {
/* Always given in blocks of 2 KiB.
Written to the ISO image according to Ecma119Image.apm_block_size.
*/
uint32_t start_block;
uint32_t block_count;
/* All 32 bytes get copied to the system area.
Take care to pad up short strings by 0.
*/
uint8_t name[32];
uint8_t type[32];
};
/* Copies the content of req and registers it in t.apm_req[].
I.e. after the call the submitted storage of req can be disposed or re-used.
Submit 0 as value flag.
*/
int iso_register_apm_entry(Ecma119Image *t,
struct iso_apm_partition_request *req, int flag);
/* Convenience frontend for iso_register_apm_entry().
name and type are 0-terminated strings, which may get silently truncated.
*/
int iso_quick_apm_entry(Ecma119Image *t,
uint32_t start_block, uint32_t block_count, char *name, char *type);
#endif /* SYSTEM_AREA_H_ */