Browse Source

Implemented basic eltorito

master
Mario Danic 15 years ago
parent
commit
7faf1635a0
  1. 4
      Makefile.am
  2. 29
      TODO
  3. 31
      libisofs/ecma119.c
  4. 16
      libisofs/ecma119.h
  5. 40
      libisofs/ecma119_tree.c
  6. 5
      libisofs/ecma119_tree.h
  7. 454
      libisofs/eltorito.c
  8. 60
      libisofs/eltorito.h
  9. 19
      libisofs/joliet.c
  10. 4
      libisofs/joliet.h
  11. 98
      libisofs/libisofs.h
  12. 54
      libisofs/tree.c
  13. 20
      libisofs/tree.h
  14. 108
      libisofs/volume.c
  15. 2
      libisofs/volume.h
  16. 25
      test/iso.c

4
Makefile.am

@ -31,7 +31,9 @@ libisofs_libisofs_la_SOURCES = \
libisofs/hash.h \
libisofs/hash.c \
libisofs/file.h \
libisofs/file.c
libisofs/file.c \
libisofs/eltorito.h \
libisofs/eltorito.c
libinclude_HEADERS = \
libisofs/libisofs.h

29
TODO

@ -0,0 +1,29 @@
FEATURES
========
El-Torito
Support for multiple images
HFS/HFS+
CD reading
Multisession
UDF
ISO relaxed contraints
ISO 9660:1998
Support for special files (only dirs, reg. files and symlinks are supported).
TESTS
=====
For all
IMPLEMENTATION
==============
a way to return NULL sources meaning a failure!!
Error message queue
Public API for all things already implemented
Better charset support
default input charset to locale one, no always UTF-8

31
libisofs/ecma119.c

@ -19,6 +19,7 @@
#include "file.h"
#include "libisofs.h"
#include "libburn/libburn.h"
#include "eltorito.h"
/* burn-source compatible stuff */
static int
@ -78,6 +79,7 @@ static const write_fn writers[] =
NULL,
wr_system_area,
wr_pri_vol_desc,
el_torito_wr_boot_vol_desc,
joliet_wr_sup_vol_desc,
wr_vol_desc_term,
wr_l_path_table,
@ -86,6 +88,7 @@ static const write_fn writers[] =
joliet_wr_m_path_table,
wr_dir_records,
joliet_wr_dir_records,
el_torito_wr_catalog,
wr_files
};
@ -297,6 +300,9 @@ ecma119_target_new(struct iso_volset *volset,
t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0;
t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0;
t->catalog = volset->volume[volnum]->bootcat;
t->eltorito = t->catalog ? 1 : 0;
t->root = ecma119_tree_create(t, iso_root);
if (t->joliet)
t->joliet_root = joliet_tree_create(t, iso_root);
@ -337,6 +343,8 @@ ecma119_target_new(struct iso_volset *volset,
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
if (t->eltorito)
t->curblock += 1; /* boot record volume descriptor */
if (t->joliet) /* supplementary vol desc */
t->curblock += div_up (2048, t->block_size);
@ -363,7 +371,20 @@ ecma119_target_new(struct iso_volset *volset,
/* reset curfile when we're finished */
t->curfile = 0;
}
/* el-torito? */
if (t->eltorito) {
/* add catalog block */
t->catalog->file->block = t->curblock;
t->curblock += div_up(2048, t->block_size);
el_torito_get_image_files(t);
}
calc_file_pos(t, t->root);
if (t->eltorito)
el_torito_patch_image_files(t);
if (t->rockridge) {
susp_finalize(t, t->root);
@ -389,11 +410,19 @@ is_joliet_state(enum ecma119_write_state state)
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
}
static int
is_eltorito_state(enum ecma119_write_state state)
{
return state == ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC
|| state == ECMA119_WRITE_ELTORITO_CATALOG;
}
static void
next_state(struct ecma119_write_target *t)
{
t->state++;
while (!t->joliet && is_joliet_state(t->state))
while ( (!t->joliet && is_joliet_state(t->state))
||(!t->eltorito && is_eltorito_state(t->state)) )
t->state++;
printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock);

16
libisofs/ecma119.h

@ -29,6 +29,7 @@ enum ecma119_write_state
ECMA119_WRITE_SYSTEM_AREA,
ECMA119_WRITE_PRI_VOL_DESC,
ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC,
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
ECMA119_WRITE_VOL_DESC_TERMINATOR,
ECMA119_WRITE_L_PATH_TABLE,
@ -37,6 +38,7 @@ enum ecma119_write_state
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
ECMA119_WRITE_DIR_RECORDS,
ECMA119_WRITE_DIR_RECORDS_JOLIET,
ECMA119_WRITE_ELTORITO_CATALOG,
ECMA119_WRITE_FILES,
ECMA119_WRITE_DONE
@ -61,6 +63,9 @@ struct ecma119_write_target
unsigned int rockridge:1;
unsigned int joliet:1;
unsigned int iso_level:2;
unsigned int eltorito:1;
struct el_torito_boot_catalog *catalog;
int replace_mode; /**< Replace ownership and modes of files
*
@ -252,6 +257,17 @@ struct ecma119_sup_vol_desc
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_boot_rec_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t boot_sys_id BP(8, 39);
uint8_t boot_id BP(40, 71);
uint8_t boot_catalog BP(72, 75);
uint8_t unused BP(76, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);

40
libisofs/ecma119_tree.c

@ -9,6 +9,7 @@
#include "ecma119_tree.h"
#include "tree.h"
#include "util.h"
#include "eltorito.h"
static size_t calc_dirent_len(struct ecma119_tree_node *n)
{
@ -200,6 +201,33 @@ create_symlink(struct ecma119_write_target *t,
return ret;
}
static struct ecma119_tree_node*
create_boot_catalog(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_boot_catalog *iso)
{
struct ecma119_tree_node *ret;
struct iso_file *file;
assert(t && iso && parent && parent->type == ECMA119_DIR);
/*
* This will simply create a ECMA119 file, with the only difference
* that the iso_file is not taken from table, but from boot catalog
*/
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->type = ECMA119_FILE;
file = iso->catalog->file;
file->ino = ++t->ino;
ret->attrib.st_nlink = file->nlink;
ret->attrib.st_ino = file->ino;
ret->info.file = file;
return ret;
}
static struct ecma119_tree_node*
create_tree(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
@ -212,18 +240,18 @@ create_tree(struct ecma119_write_target *t,
if ( iso->hide_flags & LIBISO_HIDE_ON_RR )
return NULL;
switch (iso->attrib.st_mode & S_IFMT) {
case S_IFREG:
switch ( iso->type ) {
case LIBISO_NODE_FILE:
ret = create_file(t, parent, (struct iso_tree_node_file*)iso);
break;
case S_IFLNK:
case LIBISO_NODE_SYMLINK:
if ( !t->rockridge )
printf("Can't add symlinks to a non ISO tree. Skipping %s \n",
iso->name);
else
ret = create_symlink(t, parent, (struct iso_tree_node_symlink*)iso);
break;
case S_IFDIR:
case LIBISO_NODE_DIR:
{
size_t i;
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir*)iso;
@ -236,6 +264,10 @@ create_tree(struct ecma119_write_target *t,
}
}
break;
case LIBISO_NODE_BOOTCATALOG:
ret = create_boot_catalog(t, parent,
(struct iso_tree_node_boot_catalog*)iso);
break;
default:
/* should never happen */
assert( 0 );

5
libisofs/ecma119_tree.h

@ -17,7 +17,7 @@
struct ecma119_write_target;
struct iso_tree_node;
enum {
enum ecma119_node_type {
ECMA119_FILE,
ECMA119_SYMLINK,
ECMA119_DIR,
@ -58,14 +58,13 @@ struct ecma119_tree_node
* not including SU. */
struct ecma119_tree_node *parent;
/*struct iso_tree_node *iso_self;*/
struct ecma119_write_target *target;
struct stat attrib;
struct susp_info susp;
int type; /**< file, symlink, directory or placeholder */
enum ecma119_node_type type; /**< file, symlink, directory or placeholder */
union {
struct iso_file *file;
char *dest;

454
libisofs/eltorito.c

@ -0,0 +1,454 @@
#include "libisofs.h"
#include "eltorito.h"
#include "volume.h"
#include "util.h"
#include <assert.h>
#include <malloc.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
struct el_torito_validation_entry {
uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
/**
* This table should be written with accuracy values at offset
* 8 of boot image, when used ISOLINUX boot loader
*/
struct boot_info_table {
uint8_t bi_pvd BP(1, 4); /* LBA of primary volume descriptor */
uint8_t bi_file BP(5, 8); /* LBA of boot file */
uint8_t bi_length BP(9, 12); /* Length of boot file */
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
uint8_t bi_reserved BP(17, 56); /* Reserved */
};
struct partition_desc {
uint8_t boot_ind;
uint8_t begin_chs[3];
uint8_t type;
uint8_t end_chs[3];
uint8_t start[4];
uint8_t size[4];
};
struct hard_disc_mbr {
uint8_t code_area[440];
uint8_t opt_disk_sg[4];
uint8_t pad[2];
struct partition_desc partition[4];
uint8_t sign1;
uint8_t sign2;
};
static struct el_torito_boot_image *
create_image(struct iso_tree_node *image,
enum eltorito_boot_media_type type)
{
struct el_torito_boot_image *boot;
int boot_media_type = 0;
int load_sectors = 0; /* number of sector to load */
unsigned char partition_type = 0;
switch (type) {
case ELTORITO_FLOPPY_EMUL:
switch (image->attrib.st_size) {
case 1200 * 1024:
boot_media_type = 1; /* 1.2 meg diskette */
break;
case 1440 * 1024:
boot_media_type = 2; /* 1.44 meg diskette */
break;
case 2880 * 1024:
boot_media_type = 3; /* 2.88 meg diskette */
break;
default:
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", (int) image->attrib.st_size / 1024);
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
return NULL;
break;
}
/* it seems that for floppy emulation we need to load
* a single sector (512b) */
load_sectors = 1;
break;
case ELTORITO_HARD_DISC_EMUL:
{
size_t i;
int fd;
struct hard_disc_mbr mbr;
int used_partition;
/* read the MBR on disc and get the type of the partition */
fd = open(((struct iso_tree_node_file*)image)->path, O_RDONLY);
if ( fd == -1 ) {
fprintf(stderr, "Can't open image file\n");
return NULL;
}
if ( read(fd, &mbr, sizeof(mbr)) ) {
fprintf(stderr, "Can't read MBR from image file\n");
close(fd);
return NULL;
}
close(fd);
/* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
fprintf(stderr, "Invalid MBR. Wrong signature.\n");
return NULL;
}
/* ensure single partition */
used_partition = -1;
for (i = 0; i < 4; ++i) {
if (mbr.partition[i].type != 0) {
/* it's an used partition */
if (used_partition != -1) {
fprintf(stderr, "Invalid MBR. At least 2 paritions: %d and "
"%d, are being used\n", used_partition, i);
return NULL;
} else
used_partition = i;
}
}
partition_type = mbr.partition[used_partition].type;
}
boot_media_type = 4;
/* only load the MBR */
load_sectors = 1;
break;
case ELTORITO_NO_EMUL:
boot_media_type = 0;
break;
}
boot = calloc(1, sizeof(struct el_torito_boot_image));
boot->bootable = 1;
boot->image = (struct iso_tree_node_file *) image;
boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type;
return boot;
}
static struct iso_tree_node_boot_catalog*
create_boot_catalog_node(struct iso_tree_node_dir *parent,
const char *name)
{
struct iso_tree_node_boot_catalog *boot;
assert( parent && name );
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog));
boot->node.attrib.st_mode = S_IFREG | 0444;
boot->node.attrib.st_atime =
boot->node.attrib.st_mtime =
boot->node.attrib.st_ctime = time(NULL);
boot->node.type = LIBISO_NODE_BOOTCATALOG;
boot->node.name = strdup(name);
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
return boot;
}
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name)
{
struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot_catalog *boot_node;
struct el_torito_boot_catalog *catalog;
assert( volume && !volume->bootcat);
assert( image && ISO_ISREG(image) && dir && name);
boot_image = create_image(image, type);
if ( !boot_image )
return NULL;
/* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
catalog->nentries = 1;
catalog->entries = malloc(sizeof(struct el_torito_boot_image *));
catalog->entries[0] = boot_image;
catalog->file = malloc(sizeof(struct iso_file));
catalog->file->size = 2048;
/* add catalog file */
boot_node = create_boot_catalog_node(dir, name);
boot_node->catalog = catalog;
volume->bootcat = catalog;
return boot_image;
}
void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
{
if (bootimg->type != ELTORITO_NO_EMUL)
return;
bootimg->load_seg = segment;
}
void
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors)
{
if (bootimg->type != ELTORITO_NO_EMUL)
return;
bootimg->load_size = sectors;
}
void
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
{
bootimg->bootable = 0;
}
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg)
{
bootimg->patch_isolinux = 1;
}
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{
size_t i;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
free(cat->entries[i]);
}
free(cat->entries);
free(cat->file);
free(cat);
}
void el_torito_get_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
struct iso_tree_node_file *image = cat->entries[i]->image;
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
if ( file == NULL ) {
file = iso_file_new(image);
iso_file_table_add_file(t->file_table, file);
}
cat->entries[i]->file = file;
}
}
/**
* Write the Boot Record Volume Descriptor
*/
static void
write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
struct ecma119_boot_rec_vol_desc *vol =
(struct ecma119_boot_rec_vol_desc*)buf;
assert(cat);
vol->vol_desc_type[0] = 0;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
iso_lsb(vol->boot_catalog, cat->file->block, 4);
}
static void
write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
{
size_t i;
int checksum;
struct el_torito_validation_entry *ve =
(struct el_torito_validation_entry*)buf;
ve->header_id[0] = 1;
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
ve->key_byte1[0] = 0x55;
ve->key_byte2[0] = 0xAA;
/* calculate the checksum, to ensure sum of all words is 0 */
checksum = 0;
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
checksum -= buf[i];
checksum -= (buf[i] << 8);
}
iso_lsb(ve->checksum, checksum, 2);
}
static void
patch_boot_file(struct el_torito_boot_image *img)
{
struct boot_info_table info;
int fd;
uint32_t checksum;
ssize_t len;
uint8_t buf[4];
memset(&info, 0, sizeof(info));
/* open image */
fd = open(img->image->path, O_RDWR);
if ( fd == -1 ) {
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
lseek(fd, (off_t) 64, SEEK_SET);
//TODO this can (must) be optimizied by reading to a longer buffer
while ( (len = read(fd, buf, 4) ) == 4 ) {
checksum += iso_read_lsb(buf, 4);
}
if ( len != 0 ) {
/* error reading file, or file length not multiple of 4 */
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
}
/* fill boot info table */
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
iso_lsb(info.bi_file, img->file->block, 4);
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4);
iso_lsb(info.bi_csum, checksum, 4);
/* patch file */
lseek(fd, (off_t) 8, SEEK_SET);
write(fd, &info, sizeof(info));
close(fd);
}
void
el_torito_patch_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for (i = 0; i < cat->nentries; ++i) {
struct el_torito_boot_image *img = cat->entries[i];
if ( img->patch_isolinux )
patch_boot_file(img);
}
}
/**
* Write one section entry.
* Currently this is used for both default and other entries since we
* put selection criteria no 0 (no sel. criteria)
*/
static void
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img)
{
struct el_torito_section_entry *se =
(struct el_torito_section_entry*)buf;
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
se->boot_media_type[0] = img->type;
iso_lsb(se->load_seg, img->load_seg, 2);
se->system_type[0] = 0; //TODO need to get the partition type
iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, img->file->block, 4);
}
/**
* Write El-Torito Boot Catalog
*/
static void
write_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
assert(cat->nentries >= 1 && cat->nentries < 63);
write_validation_entry(t, buf);
/* write default entry */
write_section_entry(buf + 32, cat->entries[0]);
//TODO write all images
}
void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
assert(t->catalog);
ecma119_start_chunking(t,
write_boot_vol_desc,
2048,
buf);
}
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
assert(t->catalog);
ecma119_start_chunking(t,
write_catalog,
2048,
buf);
}

60
libisofs/eltorito.h

@ -0,0 +1,60 @@
#ifndef ELTORITO_H_
#define ELTORITO_H_
#include "tree.h"
#include "file.h"
#include "ecma119.h"
/**
* Location of the boot catalog
*/
struct iso_tree_node_boot_catalog
{
struct iso_tree_node node;
struct el_torito_boot_catalog *catalog;
};
struct el_torito_boot_catalog {
int nentries;
struct el_torito_boot_image **entries;
struct iso_file *file; /**< The catalog file */
};
struct el_torito_boot_image {
unsigned char bootable; /**< If the entry is bootable. */
unsigned char patch_isolinux; /**< If the image will be patched */
unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sector to load. */
struct iso_tree_node_file *image;
struct iso_file *file;
};
/*struct el_torito_boot_entry *
el_torito_add_boot_entry(struct el_torito_boot_catalog *cat,
struct iso_tree_node_file *image);
*/
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
/**
* For each boot image file, this gets the related iso_file object.
* In most cases, the file is already in the hash table. However, if the
* boot record is hidden in both ISO/RR and joliet trees, this ensures
* that boot images will be written to image.
*/
void el_torito_get_image_files(struct ecma119_write_target *t);
/**
* Patch image files if selected. This is needed for isolinux boot images
*/
void el_torito_patch_image_files(struct ecma119_write_target *t);
void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);
#endif /*ELTORITO_H_*/

19
libisofs/joliet.c

@ -7,6 +7,7 @@
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "eltorito.h"
#include <assert.h>
#include <string.h>
@ -28,7 +29,7 @@ create_node(struct ecma119_write_target *t,
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *) iso;
ret->info.dir.children = calloc(sizeof(void*), dir->nchildren);
ret->type = JOLIET_DIR;
} else {
} else if (ISO_ISREG(iso)) {
/* it's a file */
struct iso_tree_node_file *iso_f = (struct iso_tree_node_file *) iso;
struct iso_file *file;
@ -39,6 +40,14 @@ create_node(struct ecma119_write_target *t,
}
ret->info.file = file;
ret->type = JOLIET_FILE;
} else {
/* it's boot catalog info */
struct iso_tree_node_boot_catalog *iso_b =
(struct iso_tree_node_boot_catalog *) iso;
struct iso_file *file;
file = iso_b->catalog->file;
ret->info.file = file;
ret->type = JOLIET_FILE;
}
return ret;
@ -55,11 +64,12 @@ create_tree(struct ecma119_write_target *t,
if ( iso->hide_flags & LIBISO_HIDE_ON_JOLIET )
return NULL;
switch (iso->attrib.st_mode & S_IFMT) {
case S_IFREG:
switch (iso->type) {
case LIBISO_NODE_FILE:
case LIBISO_NODE_BOOTCATALOG:
root = create_node(t, parent, iso);
break;
case S_IFDIR:
case LIBISO_NODE_DIR:
{
size_t i;
struct joliet_tree_node *node;
@ -320,7 +330,6 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
vol->vol_desc_type[0] = 2;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->system_id, "SYSID", 5);
if (vol_id)
memcpy(vol->volume_id, vol_id, vol_id_len);
memcpy(vol->esc_sequences, "%/E", 3);

4
libisofs/joliet.h

@ -17,7 +17,7 @@
struct ecma119_write_target;
struct iso_tree_node;
enum {
enum joliet_node_type {
JOLIET_FILE,
JOLIET_DIR
};
@ -37,7 +37,7 @@ struct joliet_tree_node
struct joliet_tree_node *parent;
struct ecma119_write_target *target;
int type;
enum joliet_node_type type;
union {
struct iso_file *file;
struct joliet_dir_info dir;

98
libisofs/libisofs.h

@ -35,6 +35,12 @@ struct iso_volset;
*/
struct iso_tree_node;
/**
* El-Torito boot image
* \see eltorito.h
*/
struct el_torito_boot_image;
/**
* A directory in the filesystem tree.
* The first member of this is an iso_tree_node.
@ -52,6 +58,12 @@ enum hide_node_flag {
LIBISO_HIDE_ON_JOLIET = 1 << 1
};
enum eltorito_boot_media_type {
ELTORITO_FLOPPY_EMUL,
ELTORITO_HARD_DISC_EMUL,
ELTORITO_NO_EMUL
};
/**
* This will hold the error code for some functions, if them fail.
*/
@ -65,6 +77,8 @@ int libisofs_errno;
#define NO_READ_ACCESS 2
/* unexpected file type, eg., passing a dir instead of a regular file */
#define UNEXPECTED_FILE_TYPE 3
/* invalid boot image size */
#define ELTORITO_WRONG_IMAGE_SIZE 4
/**
* Controls the bahavior of iso_tree_radd_dir function
@ -157,6 +171,71 @@ void iso_volume_set_abstract_file_id(struct iso_volume *volume,
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id);
/**
* Create a bootable volume by adding a El-Torito boot image.
*
* \param volume The volume to make bootable.
* \param image The tree node with the file to use as default boot image.
* \param type The boot media type. This can be one of 3 types:
* - Floppy emulation: Boot image files must be exactly
* 1200 kB, 1440 kB or 2880 kB.
* - Hard disc emulation: The image must begin with a master
* boot record with a single image.
* - No emulation. You should specify load segment and load size
* of image.
* \param dir The directory node where the boot catalog will be located
* in image. Usually both boot catalog and boot image will be
* located in the same dir, maybe /boot.
* \param name The name of the boot catalog.
*
* \return The default El-Torito bootable image. If specified image file
* seems to be not correct, this returns NULL and libisofs_errno
* is set propertly.
*
* \pre \p volume is a volume without any boot catalog yet
* \pre \p image is a file tree node already inserted in the volume tree.
* \pre \p dir is a directory node already inserted in the volume tree.
* \pre \p name There isn't any dir child with the same name.
*
*/
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name);
/**
* Sets the load segment for the initial boot image. This is only for
* no emulation boot images, and is a NOP for other image types.
*/
void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment);
/**
* Sets the number of sectors (512b) to be load at load segment during
* the initial boot procedure. This is only for
* no emulation boot images, and is a NOP for other image types.
*/
void
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors);
/**
* Marks the specified boot image as not bootable
*/
void
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg);
/**
* Specifies that this image needs to be patched. This involves the writting
* of a 56 bytes boot information table at offset 8 of the boot image file.
* Be aware that libisofs will modify original boot image file, so do a backup
* if needed.
* This is needed for isolinux boot images.
*/
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
/**
* Locate a node by its path on disc.
*
@ -165,8 +244,10 @@ void iso_volume_set_biblio_file_id(struct iso_volume *volume,
*
* \return The node found or NULL.
*
* TODO we need a way to allow developers know which kind of node is.
* Think about this when designing the read api
*/
//struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
/**
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
@ -284,10 +365,9 @@ struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
* \pre \p parent is non-NULL.
* \pre \p path is non-NULL and is a valid path to a directory on the local
* filesystem.
* \return a pointer to the newly created directory.
*/
struct iso_tree_node_dir *iso_tree_radd_dir(struct iso_tree_node_dir *parent,
const char *path, struct iso_tree_radd_dir_behavior *behavior);
void iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior);
/**
* Set the name of a tree node (using the current locale).
@ -353,6 +433,16 @@ void iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w);
*/
void iso_tree_print(const struct iso_tree_node *root, int spaces);
/**
* Holds the options for the image generation.
*/
//struct ecma119_source_opts {
// int volnum; /**< The volume in the set which you want to write (usually 0) */
// int level; /**< ISO level to write at. */
// int flags; /**< Which extensions to support. */
//};
/** Create a burn_source which can be used as a data source for a track
*
* The volume set used to create the libburn_source can _not_ be modified

54
libisofs/tree.c

@ -32,9 +32,9 @@ set_default_stat(struct stat *s)
s->st_atime = s->st_mtime = s->st_ctime = now;
}
static void
append_node(struct iso_tree_node_dir *parent,
struct iso_tree_node *child)
void
iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child)
{
assert( parent && child);
@ -54,6 +54,7 @@ iso_tree_new_root()
set_default_stat(&root->node.attrib);
root->node.attrib.st_mode = S_IFDIR | 0777;
root->node.type = LIBISO_NODE_DIR;
return root;
}
@ -86,13 +87,14 @@ iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
/* fill fields */
f->node.attrib = st;
f->path = strdup(path);
f->node.type = LIBISO_NODE_FILE;
p = strdup(path); /* because basename() might modify its arg */
f->node.name = strdup( basename(p) );
free(p);
/* add to parent (this also sets f->node->parent) */
append_node(parent, (struct iso_tree_node*) f);
iso_tree_add_child(parent, (struct iso_tree_node*) f);
return (struct iso_tree_node*) f;
}
@ -109,12 +111,13 @@ iso_tree_add_symlink(struct iso_tree_node_dir *parent,
/* fill fields */
set_default_stat(&link->node.attrib);
link->node.attrib.st_mode |= S_IFLNK;
link->node.attrib.st_mode |= S_IFLNK;//TODO Not needed
link->node.name = strdup(name);
link->node.type = LIBISO_NODE_SYMLINK;
link->dest = strdup(dest);
/* add to parent (this also sets link->node->parent) */
append_node(parent, (struct iso_tree_node*) link);
iso_tree_add_child(parent, (struct iso_tree_node*) link);
return (struct iso_tree_node*) link;
}
@ -130,9 +133,10 @@ iso_tree_add_dir(struct iso_tree_node_dir *parent,
dir = calloc(1, sizeof(struct iso_tree_node_dir));
dir->node.attrib = parent->node.attrib;
dir->node.type = LIBISO_NODE_DIR;
dir->node.name = strdup(name);
append_node(parent, (struct iso_tree_node*) dir);
iso_tree_add_child(parent, (struct iso_tree_node*) dir);
return dir;
}
@ -276,7 +280,7 @@ iso_tree_free(struct iso_tree_node *root)
free(root);
}
static struct iso_tree_node*
static void
iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior,
struct iso_hash_table *excludes)
@ -285,20 +289,18 @@ iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
DIR *dir;
struct dirent *ent;
new = iso_tree_add_node(parent, path);
if (!new || !ISO_ISDIR(new)) {
return new;
}
dir = opendir(path);
if (!dir) {
warn("couldn't open directory %s: %s\n", path, strerror(errno));
return new;
return;
}
while ((ent = readdir(dir))) {
char child[strlen(ent->d_name) + strlen(path) + 2];
if (behavior->stop_on_error & behavior->error)
break;
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
continue;
@ -310,20 +312,23 @@ iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
if (iso_exclude_lookup(excludes, child))
continue;
if ( !iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
behavior, excludes) ) {
/* error */
behavior->error = 1;
if (behavior->stop_on_error)
break;
new = iso_tree_add_node(parent, child);
if (!new || !ISO_ISDIR(new)) {
if (!new)
behavior->error = 1;
continue;
}
iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
behavior, excludes);
}
closedir(dir);
return new;
return;
}
struct iso_tree_node_dir*
void
iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior)
{
@ -344,8 +349,7 @@ iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
}
/* recurse into dir */
dir = (struct iso_tree_node_dir*) iso_tree_radd_dir_aux(
parent, path, behavior, &table);
iso_tree_radd_dir_aux(parent, path, behavior, &table);
/* clear hashtable */
iso_exclude_empty(&table);
@ -382,7 +386,7 @@ iso_tree_print_verbose(const struct iso_tree_node *root,
int spaces)
{
(S_ISDIR(root->attrib.st_mode) ? dir : file)
(ISO_ISDIR(root) ? dir : file)
(root, callback_data, spaces);
if ( ISO_ISDIR(root) ) {

20
libisofs/tree.h

@ -44,6 +44,13 @@
// /* };*/
//};
enum iso_tree_node_type {
LIBISO_NODE_DIR,
LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOTCATALOG
};
/**
* A node in the filesystem tree.
*/
@ -56,6 +63,7 @@ struct iso_tree_node
int hide_flags; /**< If the node is to be hidden in RR/ISO or
* Joilet tree */
enum iso_tree_node_type type;
};
/**
@ -112,6 +120,12 @@ struct iso_tree_node_dir
*/
void iso_tree_free(struct iso_tree_node *root);
/**
* Adds a child to a directory
*/
void iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child);
/**
* A function that prints verbose information about a directory.
*
@ -156,8 +170,8 @@ void iso_tree_print_verbose(const struct iso_tree_node *root,
void *callback_data,
int spaces);
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
#define ISO_ISREG(n) S_ISREG(n->attrib.st_mode)
#define ISO_ISLNK(n) S_ISLNK(n->attrib.st_mode)
#define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR)
#define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE)
#define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK)
#endif /* LIBISO_TREE_H */

108
libisofs/volume.c

@ -9,6 +9,7 @@
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "eltorito.h"
struct iso_volset*
iso_volset_new(struct iso_volume *vol, const char *id)
@ -80,7 +81,13 @@ iso_volume_free(struct iso_volume *volume)
free(volume->volume_id);
free(volume->publisher_id);
free(volume->data_preparer_id);
free(volume->system_id);
free(volume->application_id);
free(volume->copyright_file_id);
free(volume->abstract_file_id);
free(volume->biblio_file_id);
if (volume->bootcat)
el_torito_boot_catalog_free(volume->bootcat);
free(volume);
}
}
@ -139,52 +146,59 @@ void iso_volume_set_biblio_file_id(struct iso_volume *volume,
volume->biblio_file_id = strdup(biblio_file_id);
}
//struct iso_tree_node *
//iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
//{
// struct iso_tree_node *node;
// char *ptr, *brk_info, *component;
//
// /* get the first child at the root of the volume
// * that is "/" */
// node=iso_volume_get_root(volume);
// if (!strcmp (path, "/"))
// return node;
//
// if (!node->nchildren)
// return NULL;
//
// /* the name of the nodes is in wide characters so first convert path
// * into wide characters. */
// ptr = strdup(path);
//
// /* get the first component of the path */
// component=strtok_r(ptr, "/", &brk_info);
// while (component) {
// size_t max;
// size_t i;
//
// /* search among all the children of this directory if this path component exists */
// max=node->nchildren;
// for (i=0; i < max; i++) {
// if (!strcmp(component, node->children[i]->name)) {
// node=node->children[i];
// break;
// }
// }
//
// /* see if a node could be found */
// if (i==max) {
// node=NULL;
// break;
// }
//
// component=strtok_r(NULL, "/", &brk_info);
// }
//
// free(ptr);
// return node;
//}
struct iso_tree_node *
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
{
struct iso_tree_node *node;
struct iso_tree_node_dir *dir;
char *ptr, *brk_info, *component;
/* get the first child at the root of the volume
* that is "/" */
dir = iso_volume_get_root(volume);
node = (struct iso_tree_node *)dir;
if (!strcmp(path, "/"))
return node;
if (!dir->nchildren)
return NULL;
ptr = strdup(path);
/* get the first component of the path */
component=strtok_r(ptr, "/", &brk_info);
while (component) {
size_t max;
size_t i;
if ( !ISO_ISDIR(node) ) {
node=NULL;
break;
}
dir = (struct iso_tree_node_dir *)node;
/* search among all the children of this directory if this path component exists */
max=dir->nchildren;
for (i=0; i < max; i++) {
if (!strcmp(component, dir->children[i]->name)) {
node=dir->children[i];
break;
}
}
/* see if a node could be found */
if (i==max) {
node=NULL;
break;
}
component=strtok_r(NULL, "/", &brk_info);
}
free(ptr);
return node;
}
//
//struct iso_tree_node *
//iso_tree_volume_add_path(struct iso_volume *volume,

2
libisofs/volume.h

@ -30,6 +30,8 @@ struct iso_volume
char *copyright_file_id;
char *abstract_file_id;
char *biblio_file_id;
struct el_torito_boot_catalog *bootcat; /**< El-Torito boot catalog */
};
/**

25
test/iso.c

@ -20,7 +20,7 @@
#define SECSIZE 2048
const char * const optstring = "JRL:h";
const char * const optstring = "JRL:b:h";
extern char *optarg;
extern int optind;
@ -36,6 +36,7 @@ void help()
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -b file Specifies a boot image to add to image\n"
" -h Print this message\n"
);
}
@ -51,6 +52,7 @@ int main(int argc, char **argv)
int c;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
char *boot_img = NULL;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
@ -68,6 +70,9 @@ int main(int argc, char **argv)
case 'L':
level = atoi(optarg);
break;
case 'b':
boot_img = optarg;
break;
case '?':
usage();
exit(1);
@ -96,9 +101,25 @@ int main(int argc, char **argv)
err(1, "error opening input directory");
}
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
if ( boot_img ) {
/* adds El-Torito boot info. Tunned for isolinux */
struct iso_tree_node_dir *boot = (struct iso_tree_node_dir *)
iso_tree_volume_path_to_node(volume, "isolinux");
struct iso_tree_node *img = iso_tree_volume_path_to_node(volume, boot_img);
if (!img) {
err(1, "boot image patch is not valid");
}
struct el_torito_boot_image *bootimg =
iso_volume_create_boot_catalog(volume, img, ELTORITO_NO_EMUL,
boot, "boot.cat");
el_torito_set_load_size(bootimg, 4);
el_torito_set_write_boot_info(bootimg);
}
volset = iso_volset_new( volume, "VOLSETID" );
//some tests
/* some tests */
iso_volume_set_application_id(volume, "Libburnia");
iso_volume_set_copyright_file_id(volume, "LICENSE");

Loading…
Cancel
Save