New API object iso_interval_reader. Enabling flag bits for older API calls

iso_write_opts_set_prep_img(), iso_write_opts_set_efi_bootp(),
and iso_write_opts_set_partition_img().
release-1.5.4.branch
Thomas Schmitt 8 years ago
parent a0719328ea
commit d4b8cbe474
  1. 582
      libisofs/ecma119.c
  2. 3
      libisofs/ecma119.h
  3. 20
      libisofs/fs_image.c
  4. 3
      libisofs/image.c
  5. 7
      libisofs/image.h
  6. 164
      libisofs/libisofs.h
  7. 4
      libisofs/libisofs.ver
  8. 6
      libisofs/messages.c
  9. 59
      libisofs/system_area.c
  10. 38
      libisofs/util.c
  11. 14
      libisofs/util.h

@ -1483,11 +1483,519 @@ static int finish_libjte(Ecma119Image *target)
}
/* >>> need opportunity to just mark a partition in the older sessions
*/
struct iso_interval_zeroizer {
int z_type; /* 0= $zero_start"-"$zero_end ,
1= "zero_mbrpt" , 2= "zero_gpt" , 3= "zero_apm"
*/
off_t zero_start;
off_t zero_end;
};
struct iso_interval_reader {
/* Setup */
IsoImage *image;
char *path;
int flags; /* bit0= imported_iso, else local_fs
*/
off_t start_byte;
off_t end_byte;
struct iso_interval_zeroizer *zeroizers;
int num_zeroizers;
char *source_pt; /* This is a parasite pointer of path. Do not free */
/* State information */
int initialized;
int is_block_aligned;
off_t cur_block;
int fd;
uint8_t read_buf[BLOCK_SIZE];
uint8_t *pending_read_pt;
int pending_read_bytes;
off_t read_count;
int eof;
int src_is_open;
uint32_t apm_block_size;
};
static
int iso_ivr_next_comp(char *read_pt, char **next_pt, int flag)
{
*next_pt = NULL;
if (read_pt == NULL)
return 0;
*next_pt = strchr(read_pt, ':');
if (*next_pt != NULL)
(*next_pt)++;
return 1;
}
/* @param flag bit1= end number requested, forward to iso_scanf_io_size()
*/
static
int iso_ivr_read_number(char *start_pt, char *end_pt, off_t *result, int flag)
{
char txt[20];
off_t num;
if (end_pt - start_pt <= 0 || end_pt - start_pt > 16) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Number text too short or too long in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
if (end_pt - start_pt > 0)
strncpy(txt, start_pt, end_pt - start_pt);
txt[end_pt - start_pt] = 0;
num = iso_scanf_io_size(start_pt, 1 | (flag & 2));
if (num < 0.0 || num > 0xffffffffffff) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Negative or overly large number in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
*result = num;
return 1;
}
static
int iso_ivr_parse_interval(char *start_pt, char *end_pt, off_t *start_byte,
off_t *end_byte, int flag)
{
int ret;
char *m_pt;
m_pt = strchr(start_pt, '-');
if (m_pt == NULL) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Malformed byte interval in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ret = iso_ivr_read_number(start_pt, m_pt, start_byte, 0);
if (ret < 0)
return ret;
ret = iso_ivr_read_number(m_pt + 1, end_pt - 1, end_byte, 2);
if (ret < 0)
return ret;
return ISO_SUCCESS;
}
static
int iso_ivr_parse_zeroizers(struct iso_interval_reader *ivr,
char *pathpt, char *end_pt, int flag)
{
int ret, num_zs = 1, idx, i;
char *rpt, *cpt;
ivr->num_zeroizers = 0;
if (pathpt[0] == 0 || pathpt == end_pt)
return ISO_SUCCESS;
for(cpt = pathpt - 1; cpt != NULL && cpt < end_pt; num_zs++)
cpt = strchr(cpt + 1, ',');
LIBISO_ALLOC_MEM(ivr->zeroizers, struct iso_interval_zeroizer, num_zs);
for (i = 0; i < num_zs; i++)
ivr->zeroizers[i].zero_end = -1;
idx = 0;
for (rpt = pathpt; rpt != NULL && rpt < end_pt; idx++) {
cpt = strchr(rpt, ',');
if (cpt == NULL || cpt > end_pt)
cpt = end_pt;
if (cpt == rpt) {
continue;
} else if (strncmp(rpt, "zero_mbrpt", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 1;
} else if (strncmp(rpt, "zero_gpt", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 2;
} else if (strncmp(rpt, "zero_apm", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 3;
} else {
ivr->zeroizers[idx].z_type = 0;
ret = iso_ivr_parse_interval(rpt, cpt,
&(ivr->zeroizers[idx].zero_start),
&(ivr->zeroizers[idx].zero_end), 0);
if (ret < 0)
goto ex;
}
rpt = cpt + 1;
ivr->num_zeroizers++;
}
ret = ISO_SUCCESS;
ex:;
return ret;
}
static
int iso_ivr_parse(struct iso_interval_reader *ivr, char *path, int flag)
{
int ret;
char *flags_pt, *interval_pt, *zeroize_pt;
flags_pt = path;
iso_ivr_next_comp(flags_pt, &interval_pt, 0);
iso_ivr_next_comp(interval_pt, &zeroize_pt, 0);
iso_ivr_next_comp(zeroize_pt, &(ivr->source_pt), 0);
if (ivr->source_pt == NULL) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Not enough components in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ivr->flags = 0;
if (strncmp(flags_pt, "imported_iso", 12) == 0) {
ivr->flags |= 1;
} else if (strncmp(flags_pt, "local_fs", 8) == 0) {
;
} else {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Unknown flag name in first component of interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ret = iso_ivr_parse_interval(interval_pt, zeroize_pt, &(ivr->start_byte),
&(ivr->end_byte), 0);
if (ret < 0)
goto ex;
ret = iso_ivr_parse_zeroizers(ivr, zeroize_pt, ivr->source_pt - 1, 0);
if (ret < 0)
goto ex;
ret = ISO_SUCCESS;
ex:;
return ret;
}
int iso_interval_reader_destroy(struct iso_interval_reader **ivr, int flag)
{
struct iso_interval_reader *o;
if (*ivr == NULL)
return 0;
o = *ivr;
LIBISO_FREE_MEM(o->path);
LIBISO_FREE_MEM(o->zeroizers);
if (o->fd != -1)
close(o->fd);
if (o->src_is_open)
(*o->image->import_src->close)(o->image->import_src);
LIBISO_FREE_MEM(*ivr);
return ISO_SUCCESS;
}
/* @param flag bit0= tolerate lack of import_src
*/
int iso_interval_reader_new(IsoImage *img, char *path,
struct iso_interval_reader **ivr,
off_t *byte_count, int flag)
{
int ret, no_img = 0;
struct iso_interval_reader *o = NULL;
*ivr = NULL;
*byte_count = 0;
LIBISO_ALLOC_MEM(o, struct iso_interval_reader, 1);
o->image = img;
o->path = NULL;
o->zeroizers = NULL;
o->num_zeroizers = 0;
o->source_pt = NULL;
o->initialized = 0;
o->is_block_aligned = 0;
o->fd = -1;
o->pending_read_pt = NULL;
o->pending_read_bytes = 0;
o->eof = 0;
o->read_count = 0;
o->src_is_open = 0;
o->apm_block_size = 0;
LIBISO_ALLOC_MEM(o->path, char, strlen(path) + 1);
strcpy(o->path, path);
ret = iso_ivr_parse(o, path, 0);
if (ret < 0)
goto ex;
if (o->image == NULL)
no_img = 1;
else if (o->image->import_src == NULL)
no_img = 1;
if ((o->flags & 1) && no_img) {
iso_msg_submit(-1, ISO_NO_KEPT_DATA_SRC, 0,
"Interval reader lacks of data source object of imported ISO");
if (!(flag & 1)) {
ret = ISO_BAD_PARTITION_FILE;
goto ex;
}
o->eof = 1;
}
*byte_count = o->end_byte - o->start_byte + 1;
*ivr = o;
ret = ISO_SUCCESS;
ex:;
if (ret < 0)
iso_interval_reader_destroy(&o, 0);
return ret;
}
static
int iso_ivr_zeroize(struct iso_interval_reader *ivr, uint8_t *buf,
int buf_fill, int flag)
{
int i;
off_t low, high, part_start, entry_count, apm_offset = -1, map_entries;
uint8_t *apm_buf;
struct iso_interval_zeroizer *zr;
for (i = 0; i < ivr->num_zeroizers; i++) {
zr = ivr->zeroizers + i;
if (zr->z_type == 1) { /* zero_mbrpt */
if (ivr->read_count > 0 || buf_fill < 512)
continue;
if (buf[510] != 0x55 || buf[511] != 0xaa)
continue;
memset(buf + 446, 0, 64);
} else if (zr->z_type == 2) { /* zero_gpt */
if (zr->zero_start <= zr->zero_end)
goto process_interval;
if (ivr->read_count > 0 || buf_fill < 512 + 92)
continue;
if (strncmp((char *) buf + 512, "EFI PART", 8) != 0 ||
buf[520] != 0 || buf[521] != 0 || buf[522] != 1 ||
buf[523] != 0)
continue;
/* head_size , curr_lba , entry_size */
if (iso_read_lsb(buf + 524, 4) != 92 ||
iso_read_lsb(buf + 536, 4) != 1 ||
iso_read_lsb(buf + 596, 4) != 128)
continue;
part_start = iso_read_lsb(buf + 584, 4);
entry_count = iso_read_lsb(buf + 592, 4);
if (part_start < 2 || part_start + (entry_count + 3) / 4 > 64)
continue;
zr->zero_start = part_start * 512;
zr->zero_end = (part_start + (entry_count + 3) / 4) * 512 - 1;
memset(buf + 512, 0, 92);
} else if (zr->z_type == 3) { /* zero_apm */
if (zr->zero_start <= zr->zero_end)
goto process_interval;
if (ivr->read_count == 0) {
if (buf_fill < 512)
continue;
if (buf[0] != 'E' || buf[1] != 'R')
continue;
ivr->apm_block_size = iso_read_msb(buf + 2, 2);
if ((ivr->apm_block_size != 512 &&
ivr->apm_block_size != 1024 &&
ivr->apm_block_size != 2048) ||
((uint32_t) buf_fill) < ivr->apm_block_size) {
ivr->apm_block_size = 0;
continue;
}
if (ivr->read_count + buf_fill >= 2 * ivr->apm_block_size)
apm_offset = ivr->apm_block_size;
} else if (ivr->read_count == 2048 &&
ivr->apm_block_size == 2048 && buf_fill == 2048) {
apm_offset = 0;
}
if (apm_offset < 0)
continue;
/* Check for first APM entry */
apm_buf = buf + apm_offset;
if(apm_buf[0] != 'P' || apm_buf[1] != 'M')
continue;
if (iso_read_msb(apm_buf + 8, 4) != 1)
continue;
map_entries = iso_read_msb(apm_buf + 4, 4);
if ((1 + map_entries) * ivr->apm_block_size > 16 * 2048)
continue;
zr->zero_start = ivr->apm_block_size;
zr->zero_end = (1 + map_entries) * ivr->apm_block_size;
}
process_interval:;
/* If an interval is defined by now: zeroize its intersection with buf
*/
if (zr->zero_start <= zr->zero_end) {
low = ivr->read_count >= zr->zero_start ?
ivr->read_count : zr->zero_start;
high = ivr->read_count + buf_fill - 1 <= zr->zero_end ?
ivr->read_count + buf_fill - 1 : zr->zero_end;
if (low <= high)
memset(buf + low - ivr->read_count, 0, high - low + 1);
}
}
return ISO_SUCCESS;
}
int iso_interval_reader_read(struct iso_interval_reader *ivr, uint8_t *buf,
int *buf_fill, int flag)
{
int ret, read_done, to_copy, initializing = 0;
IsoDataSource *src;
uint8_t *read_buf;
off_t to_read;
*buf_fill = 0;
src = ivr->image->import_src;
if (ivr->eof) {
eof:;
memset(buf, 0, BLOCK_SIZE);
return 0;
}
if (ivr->initialized) {
ivr->cur_block++;
} else {
initializing = 1;
ivr->cur_block = ivr->start_byte / BLOCK_SIZE;
ivr->is_block_aligned = !(ivr->start_byte % BLOCK_SIZE);
if (ivr->flags & 1) {
if (src == NULL)
goto eof;
ret = (*src->open)(src);
if (ret < 0) {
ivr->eof = 1;
return ret;
}
ivr->src_is_open = 1;
} else {
ivr->fd = open(ivr->source_pt, O_RDONLY);
if (ivr->fd == -1) {
iso_msg_submit(-1, ISO_BAD_PARTITION_FILE, 0,
"Cannot open local file for interval reading");
ivr->eof = 1;
return ISO_BAD_PARTITION_FILE;
}
if (ivr->cur_block != 0) {
if (lseek(ivr->fd, ivr->cur_block * BLOCK_SIZE, SEEK_SET) ==
-1) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Cannot address interval start in local file");
ivr->eof = 1;
goto eof;
}
}
}
ivr->initialized = 1;
}
if (ivr->is_block_aligned) {
read_buf = buf;
} else {
process_pending:;
read_buf = ivr->read_buf;
/* Copy pending bytes from previous read */
if (ivr->pending_read_bytes > 0) {
memcpy(buf, ivr->pending_read_pt, ivr->pending_read_bytes);
*buf_fill = ivr->pending_read_bytes;
ivr->pending_read_bytes = 0;
}
}
/* Read next block */
read_done = 0;
if (ivr->cur_block * BLOCK_SIZE <= ivr->end_byte) {
if (ivr->flags & 1) {
ret = (*src->read_block)(src, (uint32_t) ivr->cur_block, read_buf);
if (ret < 0) {
if (iso_error_get_severity(ret) > 0x68000000) /* > FAILURE */
return ret;
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Premature EOF while interval reading from imported ISO");
ivr->eof = 1;
}
read_done = BLOCK_SIZE;
} else {
read_done = 0;
to_read = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
if (to_read > BLOCK_SIZE)
to_read = BLOCK_SIZE;
while (read_done < to_read) {
ret = read(ivr->fd, read_buf, to_read - read_done);
if (ret == -1) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Read error while interval reading from local file");
ivr->eof = 1;
break;
} else if (ret == 0) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Premature EOF while interval reading from local file");
ivr->eof = 1;
break;
} else
read_done += ret;
}
}
}
if (ivr->is_block_aligned) {
*buf_fill = read_done;
} else if (initializing) {
ivr->pending_read_pt = ivr->read_buf +
(ivr->start_byte - ivr->cur_block * BLOCK_SIZE);
ivr->pending_read_bytes = (((off_t) ivr->cur_block) + 1) * BLOCK_SIZE -
ivr->start_byte;
initializing = 0;
goto process_pending;
} else if (read_done > 0) {
/* Copy bytes from new read */
to_copy = read_done > BLOCK_SIZE - *buf_fill ?
BLOCK_SIZE - *buf_fill : read_done;
memcpy(buf + *buf_fill, ivr->read_buf, to_copy);
*buf_fill += to_copy;
ivr->pending_read_pt = ivr->read_buf + to_copy;
ivr->pending_read_bytes = read_done - to_copy;
}
if (ivr->start_byte + ivr->read_count + *buf_fill - 1 > ivr->end_byte) {
*buf_fill = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
ivr->eof = 1;
}
if (*buf_fill < BLOCK_SIZE)
memset(buf + *buf_fill, 0, BLOCK_SIZE - *buf_fill);
ret = iso_ivr_zeroize(ivr, buf, *buf_fill, 0);
if (ret < 0)
return ret;
ivr->read_count += *buf_fill;
return ISO_SUCCESS;
}
int iso_write_partition_file(Ecma119Image *target, char *path,
uint32_t prepad, uint32_t blocks, int flag)
{
struct iso_interval_reader *ivr = NULL;
int buf_fill;
off_t byte_count;
FILE *fp = NULL;
uint32_t i;
uint32_t i, intvl_blocks;
uint8_t *buf = NULL;
int ret;
@ -1498,33 +2006,46 @@ int iso_write_partition_file(Ecma119Image *target, char *path,
goto ex;
}
/* >>> need opportunity to read from input ISO image
resp. to just mark a partition in the older sessions
*/;
fp = fopen(path, "rb");
if (fp == NULL)
{ret = ISO_BAD_PARTITION_FILE; goto ex;}
for (i = 0; i < blocks; i++) {
memset(buf, 0, BLOCK_SIZE);
if (fp != NULL) {
ret = fread(buf, 1, BLOCK_SIZE, fp);
if (ret != BLOCK_SIZE) {
fclose(fp);
fp = NULL;
if (flag & 1) {
ret = iso_interval_reader_new(target->image, path,
&ivr, &byte_count, 0);
if (ret < 0)
goto ex;
intvl_blocks = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
ret = iso_interval_reader_read(ivr, buf, &buf_fill, 0);
if (ret < 0)
goto ex;
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0)
goto ex;
}
} else {
fp = fopen(path, "rb");
if (fp == NULL)
{ret = ISO_BAD_PARTITION_FILE; goto ex;}
for (i = 0; i < blocks; i++) {
memset(buf, 0, BLOCK_SIZE);
if (fp != NULL) {
ret = fread(buf, 1, BLOCK_SIZE, fp);
if (ret != BLOCK_SIZE) {
fclose(fp);
fp = NULL;
}
}
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0) {
fclose(fp);
goto ex;
}
}
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0) {
if (fp != NULL)
fclose(fp);
goto ex;
}
}
if (fp != NULL)
fclose(fp);
ret = ISO_SUCCESS;
ex:;
iso_interval_reader_destroy(&ivr, 0);
LIBISO_FREE_MEM(buf);
return ret;
}
@ -1592,9 +2113,10 @@ void *write_function(void *arg)
if (target->opts->appended_partitions[i][0] == 0)
continue;
res = iso_write_partition_file(target,
target->opts->appended_partitions[i],
target->appended_part_prepad[i],
target->appended_part_size[i], 0);
target->opts->appended_partitions[i],
target->appended_part_prepad[i],
target->appended_part_size[i],
target->opts->appended_part_flags[i] & 1);
if (res < 0)
goto write_error;
}
@ -2825,9 +3347,14 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile)
wopts->tail_blocks = 0;
wopts->prep_partition = NULL;
wopts->prep_part_flag = 0;
wopts->efi_boot_partition = NULL;
for (i = 0; i < ISO_MAX_PARTITIONS; i++)
wopts->efi_boot_part_flag = 0;
for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
wopts->appended_partitions[i] = NULL;
wopts->appended_part_types[i] = 0;
wopts->appended_part_flags[i] = 0;
}
wopts->appended_as_gpt = 0;
wopts->ascii_disc_label[0] = 0;
wopts->will_cancel = 0;
@ -3510,6 +4037,7 @@ int iso_write_opts_set_prep_img(IsoWriteOpts *opts, char *image_path, int flag)
opts->prep_partition = strdup(image_path);
if (opts->prep_partition == NULL)
return ISO_OUT_OF_MEM;
opts->prep_part_flag = (flag & 1);
return ISO_SUCCESS;
}
@ -3523,6 +4051,7 @@ int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path,
opts->efi_boot_partition = strdup(image_path);
if (opts->efi_boot_partition == NULL)
return ISO_OUT_OF_MEM;
opts->efi_boot_part_flag = (flag & 1);
return ISO_SUCCESS;
}
@ -3539,6 +4068,7 @@ int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number,
if (opts->appended_partitions[partition_number - 1] == NULL)
return ISO_OUT_OF_MEM;
opts->appended_part_types[partition_number - 1] = partition_type;
opts->appended_part_flags[partition_number - 1] = (flag & 1);
return ISO_SUCCESS;
}

@ -468,17 +468,20 @@ struct iso_write_opts {
to HFS+/FAT and IsoFileSrc areas and marked by an MBR partition entry.
*/
char *prep_partition;
int prep_part_flag;
/* Eventual disk file path of an EFI system partition image which shall
be prepended to HFS+/FAT and IsoFileSrc areas and marked by a GPT entry.
*/
char *efi_boot_partition;
int efi_boot_part_flag;
/* Eventual disk file paths of prepared images which shall be appended
after the ISO image and described by partiton table entries in a MBR
*/
char *appended_partitions[ISO_MAX_PARTITIONS];
uint8_t appended_part_types[ISO_MAX_PARTITIONS];
int appended_part_flags[ISO_MAX_PARTITIONS];
/* If 1: With appended partitions: create protective MBR and mark by GPT
*/

@ -124,6 +124,12 @@ struct iso_read_opts
* submission by iso_write_opts_set_system_area(data, 0).
*/
int load_system_area;
/**
* Keep data source of imported ISO filesystem in IsoImage.import_src
*/
int keep_import_src;
};
/**
@ -5620,6 +5626,10 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
data = fs->data;
if (opts->keep_import_src) {
iso_data_source_ref(src);
image->import_src = src;
}
if (opts->load_system_area) {
if (image->system_area_data != NULL)
free(image->system_area_data);
@ -6029,6 +6039,7 @@ int iso_read_opts_new(IsoReadOpts **opts, int profile)
ropts->noaaip = 1;
ropts->nomd5 = 1;
ropts->load_system_area = 0;
ropts->keep_import_src = 0;
*opts = ropts;
return ISO_SUCCESS;
@ -6173,6 +6184,15 @@ int iso_read_opts_load_system_area(IsoReadOpts *opts, int mode)
return ISO_SUCCESS;
}
int iso_read_opts_keep_import_src(IsoReadOpts *opts, int mode)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->keep_import_src = mode & 1;
return ISO_SUCCESS;
}
/**
* Destroy an IsoReadImageFeatures object obtained with iso_image_import.
*/

@ -185,6 +185,7 @@ int iso_image_new(const char *name, IsoImage **image)
img->hppa_kernel_64 = NULL;
img->hppa_ramdisk = NULL;
img->alpha_boot_image = NULL;
img->import_src = NULL;
img->builder_ignore_acl = 1;
img->builder_ignore_ea = 1;
img->inode_counter = 0;
@ -245,6 +246,8 @@ void iso_image_unref(IsoImage *image)
iso_image_set_hppa_palo(image, NULL, NULL, NULL, NULL, NULL, 1);
if (image->alpha_boot_image != NULL)
free(image->alpha_boot_image);
if (image->import_src != NULL)
iso_data_source_unref(image->import_src);
free(image->volset_id);
free(image->volume_id);
free(image->publisher_id);

@ -64,6 +64,8 @@ struct Iso_Image
/* Eventually loaded system area data, or NULL */
char *system_area_data;
/* Prescribed/detected options, see iso_write_opts_set_system_area() */
/* >>> Needs to be coordinated with .imported_sa_info->system_area_options
*/
int system_area_options;
/*
@ -100,6 +102,11 @@ struct Iso_Image
IsoFilesystem *fs;
/**
* Block storage of imported ISO if demanded by IsoReadOpts.
*/
IsoDataSource *import_src;
/*
* Default builder to use when adding files to the image tree.
*/
IsoNodeBuilder *builder;

@ -2409,6 +2409,117 @@ int iso_write_opts_detach_jte(IsoWriteOpts *opts, void **libjte_handle);
*/
int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks);
/**
* The libisofs interval reader is used internally and offered by libisofs API:
* @since 1.4.0
* The functions iso_write_opts_set_prep_img(), iso_write_opts_set_efi_bootp(),
* and iso_write_opts_set_partition_img() accept with their flag bit0 an
* interval reader description string instead of a disk path.
* The API calls are iso_interval_reader_new(), iso_interval_reader_read(),
* and iso_interval_reader_destroy().
* The data may be cut out and optionally partly zeroized.
*
* An interval reader description string has the form:
* $flags:$interval:$zeroizers:$source
* The component $flags modifies the further interpretation:
* "local_fs" ....... demands to read from a file depicted by the path in
* $source.
* "imported_iso" ... demands to read from the IsoDataSource object that was
* used with iso_image_import() when
* iso_read_opts_keep_import_src() was enabled.
* The text in $source is ignored.
* The application has to ensure that reading from the
* import source does not disturb production of the new
* ISO session. Especially this would be the case if the
* import source is the same libburn drive with a
* sequential optical medium to which the new session shall
* get burned.
* The component $interval consists of two byte address numbers separated
* by a "-" character. E.g. "0-429" means to read bytes 0 to 429.
* The component $zeroizers consists of zero or more comma separated strings.
* They define which part of the read data to zeroize. Byte number 0 means
* the byte read from the $interval start address.
* Each string may be either
* "zero_mbrpt" ..... demands to zeroize bytes 446 to 509 of the read data if
* bytes 510 and 511 bear the MBR signature 0x55 0xaa.
* "zero_gpt" ....... demands to check for a GPT header in bytes 512 to 1023,
* to zeroize it and its partition table blocks.
* "zero_apm" ....... demands to check for an APM block 0 and to zeroize
* its partition table blocks. But not the block 0 itself,
* because it could be actually MBR x86 machine code.
* $zero_start"-"$zero_end ... demands to zeroize the read-in bytes beginning
* with number $zero_start and ending after $zero_end.
* The component $source is the file path with "local_fs", and ignored with
* "imported_iso".
* Byte numbers may be scaled by a suffix out of {k,m,g,t,s,d} meaning
* multiplication by {1024, 1024k, 1024m, 1024g, 2048, 512}. A scaled value
* as end number depicts the last byte of the scaled range.
* E.g. "0d-0d" is "0-511".
* Examples:
* "local_fs:0-32767:zero_mbrpt,zero_gpt,440-443:/tmp/template.iso"
* "imported_iso:45056d-47103d::"
*/
struct iso_interval_reader;
/**
* Create an interval reader object.
*
* @param img
* The IsoImage object which can provide the "imported_iso" data source.
* @param path
* The interval reader description string. See above.
* @param ivr
* Returns in case of success a pointer to the created object.
* Dispose it by iso_interval_reader_destroy() when no longer needed.
* @param byte_count
* Returns in case of success the number of bytes in the interval.
* @param flag
* bit0= tolerate (src == NULL) with "imported_iso".
* (Will immediately cause eof of interval input.)
* @return
* ISO_SUCCESS or error (which is < 0)
*
* @since 1.4.0
*/
int iso_interval_reader_new(IsoImage *img, char *path,
struct iso_interval_reader **ivr,
off_t *byte_count, int flag);
/**
* Dispose an interval reader object.
*
* @param ivr
* The reader object to be disposed. *ivr will be set to NULL.
* @return
* ISO_SUCCESS or error (which is < 0)
*
* @since 1.4.0
*/
int iso_interval_reader_destroy(struct iso_interval_reader **ivr, int flag);
/**
* Read the next block of 2048 bytes from an interval reader object.
* If end-of-input happens, the interval will get filled up with 0 bytes.
*
* @param ivr
* The object to read from.
* @param buf
* Pointer to memory for filling in at least 2048 bytes.
* @param buf_fill
* Will in case of success return the number of valid bytes.
* If this is smaller than 2048, then end-of-interval has occured.
* @param flag
* Unused yet. Submit 0.
* @return
* ISO_SUCCESS if data were read, 0 if not, < 0 if error
*
* @since 1.4.0
*/
int iso_interval_reader_read(struct iso_interval_reader *ivr, uint8_t *buf,
int *buf_fill, int flag);
/**
* Copy a data file from the local filesystem into the emerging ISO image.
* Mark it by an MBR partition entry as PreP partition and also cause
@ -2427,10 +2538,14 @@ int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks);
* @param opts
* The option set to be manipulated.
* @param image_path
* File address in the local file system.
* File address in the local file system or instructions for interval
* reader. See flag bit0.
* NULL revokes production of the PreP partition.
* @param flag
* Reserved for future usage, set to 0.
* bit0= The path contains instructions for the interval reader.
* See above.
* @since 1.4.0
* All other bits are reserved for future usage. Set them to 0.
* @return
* ISO_SUCCESS or error
*
@ -2457,10 +2572,14 @@ int iso_write_opts_set_prep_img(IsoWriteOpts *opts, char *image_path,
* @param opts
* The option set to be manipulated.
* @param image_path
* File address in the local file system.
* File address in the local file system or instructions for interval
* reader. See flag bit0.
* NULL revokes production of the EFI boot partition.
* @param flag
* Reserved for future usage, set to 0.
* bit0= The path contains instructions for the interval reader
* See above.
* @since 1.4.0
* All other bits are reserved for future usage. Set them to 0.
* @return
* ISO_SUCCESS or error
*
@ -2488,7 +2607,8 @@ int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path,
* unclaimable space before partition 1.
* Range with SUN Disk Label: 2 to 8.
* @param image_path
* File address in the local file system.
* File address in the local file system or instructions for interval
* reader. See flag bit0.
* With SUN Disk Label: an empty name causes the partition to become
* a copy of the next lower partition.
* @param image_type
@ -2496,7 +2616,9 @@ int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path,
* Linux Native Partition = 0x83. See fdisk command L.
* This parameter is ignored with SUN Disk Label.
* @param flag
* bit0= The path may contain instructions for the interval reader
* bit0= The path contains instructions for the interval reader
* See above.
* @since 1.4.0
* All other bits are reserved for future usage. Set them to 0.
* @return
* ISO_SUCCESS or error
@ -2816,6 +2938,24 @@ int iso_read_opts_auto_input_charset(IsoReadOpts *opts, int mode);
*/
int iso_read_opts_load_system_area(IsoReadOpts *opts, int mode);
/**
* Control whether to keep a reference to the IsoDataSource object which
* allows access to the blocks of the imported ISO 9660 filesystem.
* This is needed if the interval reader shall read from "imported_iso".
*
* @param opts
* The option set to be manipulated
* @param mode
* Bitfield for control purposes:
* bit0= Keep a reference to the IsoDataSource until the IsoImage object
* gets disposed by its final iso_image_unref().
* Submit any other bits with value 0.
*
* @since 1.4.0
*
*/
int iso_read_opts_keep_import_src(IsoReadOpts *opts, int mode);
/**
* Import a previous session or image, for growing or modify.
*
@ -8161,7 +8301,17 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len,
#define ISO_INQ_SYSAREA_PROP 0xE830FE6C
/** DEC Alpha Boot Loader file is not a data file (FAILURE, HIGH, -405) */
#define ISO_ALPHA_BOOT_NOTREG 0xE830FE6A
#define ISO_ALPHA_BOOT_NOTREG 0xE830FE6B
/** No data source of imported ISO image available (WARNING, HIGH, -406) */
#define ISO_NO_KEPT_DATA_SRC 0xD030FE6A
/** Malformed description string for interval reader (FAILURE, HIGH, -407) */
#define ISO_MALFORMED_READ_INTVL 0xE830FE69
/** Unreadable file, premature EOF, or failure to seek for interval reader
(WARNING, HIGH, -408) */
#define ISO_INTVL_READ_PROBLEM 0xD030FE68
/* Internal developer note:

@ -141,6 +141,9 @@ iso_image_unref;
iso_image_update_sizes;
iso_init;
iso_init_with_flag;
iso_interval_reader_destroy;
iso_interval_reader_new;
iso_interval_reader_read;
iso_lib_is_compatible;
iso_lib_version;
iso_local_attr_support;
@ -216,6 +219,7 @@ iso_read_image_features_has_joliet;
iso_read_image_features_has_rockridge;
iso_read_opts_auto_input_charset;
iso_read_opts_free;
iso_read_opts_keep_import_src;
iso_read_opts_load_system_area;
iso_read_opts_new;
iso_read_opts_set_default_gid;

@ -521,6 +521,12 @@ const char *iso_error_to_msg(int errcode)
return "Unrecognized inquiry for system area property";
case ISO_ALPHA_BOOT_NOTREG:
return "DEC Alpha Boot Loader file is not a data file";
case ISO_NO_KEPT_DATA_SRC:
return "No data source of imported ISO image available";
case ISO_MALFORMED_READ_INTVL:
return "Malformed description string for interval reader";
case ISO_INTVL_READ_PROBLEM:
return "Unreadable file, premature EOF, or failure to seek for interval reader";
default:
return "Unknown error";
}

@ -107,12 +107,26 @@ void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph,
}
}
static uint32_t compute_partition_size(char *disk_path, uint32_t *size,
int flag)
/* @param flag bit0= The path contains instructions for the interval reader
*/
static int compute_partition_size(Ecma119Image *t, char *disk_path,
uint32_t *size, int flag)
{
int ret;
off_t num;
struct stat stbuf;
struct iso_interval_reader *ivr;
off_t byte_count;
if (flag & 1) {
ret = iso_interval_reader_new(t->image, disk_path,
&ivr, &byte_count, 0);
if (ret < 0)
return ret;
*size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
iso_interval_reader_destroy(&ivr, 0);
return ISO_SUCCESS;
}
*size = 0;
ret = stat(disk_path, &stbuf);
@ -150,8 +164,8 @@ int iso_compute_append_partitions(Ecma119Image *t, int flag)
continue;
if (t->opts->appended_partitions[i][0] == 0)
continue;
ret = compute_partition_size(t->opts->appended_partitions[i], &size,
0);
ret = compute_partition_size(t, t->opts->appended_partitions[i], &size,
t->opts->appended_part_flags[i]);
if (ret < 0)
return ret;
add_pos = 0;
@ -255,7 +269,7 @@ static int write_mbr_partition_entry(int partition_number, int partition_type,
*/
static
int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
uint8_t *buf, int flag)
uint8_t part_type, uint8_t *buf, int flag)
{
uint8_t *wpt;
uint32_t end_lba, end_sec, end_head, end_cyl;
@ -286,7 +300,7 @@ int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
*(wpt++) = 0;
/* 0xcd (partition type) */
*(wpt++) = 0xcd;
*(wpt++) = part_type;
/* [3 bytes of C/H/S end], */
*(wpt++) = end_head;
@ -1660,7 +1674,7 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
int first_partition = 1, last_partition = 4, apm_flag, part_type = 0;
int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0;
int offset_flag = 0;
uint32_t img_blocks, gpt_blocks, mbrp1_blocks;
uint32_t img_blocks, gpt_blocks, mbrp1_blocks, pml_blocks;
uint64_t blk;
uint8_t *wpt;
@ -1767,8 +1781,16 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
if (t->mbr_req_count == 0){
/* Write GRUB protective msdos label, i.e. a simple partition
table */
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
t->partition_heads_per_cyl, buf, 0);
if (t->gpt_req_count > 0) {
part_type = 0xee;
pml_blocks = gpt_blocks;
} else {
part_type = 0xcd;
pml_blocks = img_blocks;
}
ret = make_grub_msdos_label(pml_blocks, t->partition_secs_per_head,
t->partition_heads_per_cyl,
(uint8_t) part_type, buf, 0);
if (ret != ISO_SUCCESS) /* error should never happen */
return ISO_ASSERT_FAILURE;
}
@ -1826,7 +1848,8 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
sa_type == 0 && t->mbr_req_count == 0) {
/* Write a simple partition table. */
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
t->partition_heads_per_cyl, buf, 2);
t->partition_heads_per_cyl,
(uint8_t) 0xcd, buf, 2);
if (ret != ISO_SUCCESS) /* error should never happen */
return ISO_ASSERT_FAILURE;
if (t->opts->appended_as_gpt && t->have_appended_partitions) {
@ -1961,7 +1984,8 @@ int iso_align_isohybrid(Ecma119Image *t, int flag)
img_blocks = t->curblock + t->opts->tail_blocks + t->gpt_backup_size;
imgsize = ((off_t) img_blocks) * (off_t) 2048;
if (((t->system_area_options & 3) || always_align)
if ((!(t->opts->appended_as_gpt && t->have_appended_partitions))
&& ((t->system_area_options & 3) || always_align)
&& (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head
* 1024) * (off_t) 512 < imgsize) {
/* Choose small values which can represent the image size */
@ -2585,7 +2609,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
t->efi_boot_part_size += (src->sections[i].size + 2047) / 2048;
}
} else {
ret = compute_partition_size(t->opts->efi_boot_partition,
ret = compute_partition_size(t, t->opts->efi_boot_partition,
&(t->efi_boot_part_size), 0);
if (ret < 0)
return ret;
@ -2615,7 +2639,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
}
if (t->opts->prep_partition != NULL) {
ret = compute_partition_size(t->opts->prep_partition,
ret = compute_partition_size(t, t->opts->prep_partition,
&(t->prep_part_size), 0);
if (ret < 0)
return ret;
@ -2672,14 +2696,16 @@ static int partprepend_writer_write_data(IsoImageWriter *writer)
NULL, NULL, 0);
} else {
ret = iso_write_partition_file(t, t->opts->efi_boot_partition,
(uint32_t) 0, t->efi_boot_part_size, 0);
(uint32_t) 0, t->efi_boot_part_size,
t->opts->efi_boot_part_flag & 1);
}
if (ret < 0)
return ret;
}
if (t->opts->prep_partition != NULL && t->prep_part_size) {
ret = iso_write_partition_file(t, t->opts->prep_partition,
(uint32_t) 0, t->prep_part_size, 0);
(uint32_t) 0, t->prep_part_size,
t->opts->prep_part_flag & 1);
if (ret < 0)
return ret;
}
@ -2762,7 +2788,8 @@ static int partappend_writer_write_data(IsoImageWriter *writer)
res = iso_write_partition_file(target,
target->opts->appended_partitions[i],
target->appended_part_prepad[i],
target->appended_part_size[i], 0);
target->appended_part_size[i],
target->appended_part_flags[i] & 1);
if (res < 0)
return res;
target->curblock += target->appended_part_size[i];

@ -2305,3 +2305,41 @@ int iso_clone_mgtd_mem(char *in, char **out, size_t size)
return iso_clone_mem(in, out, size);
}
/** Convert a text into a number of type double and multiply it by unit code
[kmgt] (2^10 to 2^40) or [s] (2048) or [d] (512).
(Also accepts capital letters.)
@param text Input like "42", "223062s", "3m" or "-1g"
@param flag Bitfield for control purposes:
bit0= return -1 rathern than 0 on failure
bit1= if scaled then compute the last byte of the last unit
@return The derived value
*/
off_t iso_scanf_io_size(char *text, int flag)
{
int c;
off_t ret = 0, fac = 1;
char *rpt;
for (rpt = text; *rpt >= '0' && *rpt <= '9'; rpt++)
ret = ret * 10 + (*rpt - '0');
if (rpt == text)
return (off_t) (flag & 1 ? -1 : 0);
c = *rpt;
if (c=='k' || c=='K')
fac = 1024;
else if (c=='m' || c=='M')
fac = 1024 * 1024;
else if (c=='g' || c=='G')
fac = 1024 * 1024 * 1024;
else if (c=='t' || c=='T')
fac = ((off_t) 1024) * 1024 * 1024 * 1024;
else if (c=='s' || c=='S')
fac = 2048;
else if (c=='d' || c=='D')
fac = 512;
ret *= fac;
if (flag & 2)
ret += fac - 1;
return ret;
}

@ -21,6 +21,10 @@
#include <time.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifndef MAX
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
@ -627,6 +631,16 @@ int iso_clone_mem(char *in, char **out, size_t size);
*/
int iso_clone_mgtd_mem(char *in, char **out, size_t size);
/** Convert a text into a number of type double and multiply it by unit code
[kmgt] (2^10 to 2^40) or [s] (2048) or [d] (512).
(Also accepts capital letters.)
@param text Input like "42", "223062s", "3m" or "-1g"
@param flag Bitfield for control purposes:
bit0= return -1 rathern than 0 on failure
bit1= if scaled then compute the last byte of the last unit
@return The derived value
*/
off_t iso_scanf_io_size(char *text, int flag);
/* ------------------------------------------------------------------------- */

Loading…
Cancel
Save