Skip to content

Commit ae6732c

Browse files
committed
[iso] add basic El-Torito image parsing to libcdio
* Based on El-Torito specs found at https://pdos.csail.mit.edu/6.828/2014/readings/boot-cdrom.pdf. * Follows 7-zip's virtual '[BOOT]/#...' naming conventions (though we don't check for the full name). * Limited to 8 NoEmul images.
1 parent 2cebf91 commit ae6732c

File tree

3 files changed

+87
-7
lines changed

3 files changed

+87
-7
lines changed

src/libcdio/cdio/iso9660.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ extern enum iso_vd_enum_s {
162162
extern const char ISO_STANDARD_ID[sizeof("CD001")-1];
163163

164164
#define ISO_STANDARD_ID "CD001"
165+
#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"
165166

166167
#define CDIO_EXTENT_BLOCKS(size) ((size + (ISO_BLOCKSIZE - 1)) / ISO_BLOCKSIZE)
167168

@@ -506,6 +507,37 @@ struct iso9660_svd_s {
506507

507508
typedef struct iso9660_svd_s iso9660_svd_t;
508509

510+
/*!
511+
\brief ISO-9660 Boot Record Volume Descriptor.
512+
*/
513+
struct iso9660_brvd_s {
514+
uint8_t type; /**< ISO_VD_BOOT_RECORD - 0 */
515+
char id[5]; /**< ISO_STANDARD_ID "CD001" */
516+
uint8_t version; /**< value 1 for El Torito */
517+
char system_id[ISO_MAX_SYSTEM_ID]; /**< Boot system ID */
518+
uint8_t unused1[32]; /**< unused - value 0 */
519+
uint32_t boot_catalog_sector; /**< first sector of boot catalog */
520+
uint8_t unused2[1973]; /**< Unused - value 0 */
521+
} GNUC_PACKED;
522+
523+
typedef struct iso9660_brvd_s iso9660_brvd_t;
524+
525+
/*!
526+
\brief ISO-9660 Boot Record Volume Descriptor.
527+
*/
528+
struct iso9660_br_s {
529+
uint8_t boot_id; /**< Boot indicator - 0x88 */
530+
uint8_t media_type; /**< Boot media type - 0 for no emul. */
531+
uint16_t load_seg; /**< Load segment for x86 */
532+
uint8_t system_type; /**< System type - 0 for x86 */
533+
uint8_t unused1;
534+
uint16_t num_sectors; /**< Sector count of the image */
535+
uint32_t image_lsn; /**< Start address of the image */
536+
uint8_t unused2[20];
537+
} GNUC_PACKED;
538+
539+
typedef struct iso9660_br_s iso9660_br_t;
540+
509541
PRAGMA_END_PACKED
510542

511543
/*! \brief A data type for a list of ISO9660
@@ -582,7 +614,8 @@ extern enum iso_extension_enum_s {
582614
ISO_EXTENSION_JOLIET_LEVEL2 = 0x02,
583615
ISO_EXTENSION_JOLIET_LEVEL3 = 0x04,
584616
ISO_EXTENSION_ROCK_RIDGE = 0x08,
585-
ISO_EXTENSION_HIGH_SIERRA = 0x10
617+
ISO_EXTENSION_HIGH_SIERRA = 0x10,
618+
ISO_EXTENSION_EL_TORITO = 0x20
586619
} iso_extension_enums;
587620

588621

src/libcdio/iso9660/iso9660_fs.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#include "_cdio_stdio.h"
6060
#include "cdio_private.h"
6161

62+
#define MAX_BOOT_IMAGES 8
63+
6264
/** Implementation of iso9660_t type */
6365
struct _iso9660_s {
6466
cdio_header_t header; /**< Internal header - MUST come first. */
@@ -83,6 +85,10 @@ struct _iso9660_s {
8385
be CDIO_CD_FRAMESIZE_RAW (2352) or
8486
M2RAW_SECTOR_SIZE (2336).
8587
*/
88+
struct {
89+
uint32_t lsn; /**< Start LSN of an El-Torito bootable image */
90+
uint32_t num_sectors; /**< Number of sectors of a bootable image */
91+
} boot_img[MAX_BOOT_IMAGES];
8692
int i_fuzzy_offset; /**< Adjustment in bytes to make ISO_STANDARD_ID
8793
("CD001") come out as ISO_PVD_SECTOR
8894
(frame 16). Normally this should be 0
@@ -505,7 +511,8 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
505511
iso_extension_mask_t iso_extension_mask)
506512
{
507513
iso9660_svd_t p_svd; /* Secondary volume descriptor. */
508-
int i;
514+
iso9660_brvd_t* p_brvd = (iso9660_brvd_t*)&p_svd; /* Boot record volume descriptor. */
515+
int i, j, k;
509516

510517
if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
511518
return false;
@@ -516,6 +523,24 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
516523
for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
517524
if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
518525
break;
526+
if (iso_extension_mask & ISO_EXTENSION_EL_TORITO) {
527+
/* Check for an El-Torito boot volume descriptor */
528+
if (ISO_VD_BOOT_RECORD == from_711(p_svd.type) &&
529+
(memcmp(p_brvd->system_id, EL_TORITO_ID, ISO_MAX_SYSTEM_ID) == 0)) {
530+
/* Perform very basic parsing of boot entries to fill an image table */
531+
iso9660_br_t br[ISO_BLOCKSIZE / sizeof(iso9660_br_t)];
532+
if (iso9660_iso_seek_read(p_iso, &br, p_brvd->boot_catalog_sector, 1) == ISO_BLOCKSIZE) {
533+
for (j = 0, k = 0;
534+
j < (ISO_BLOCKSIZE / sizeof(iso9660_br_t)) && k < MAX_BOOT_IMAGES;
535+
j++) {
536+
if (br[j].boot_id == 0x88 && br[j].media_type == 0) {
537+
p_iso->boot_img[k].lsn = br[j].image_lsn;
538+
p_iso->boot_img[k++].num_sectors = br[j].num_sectors;
539+
}
540+
}
541+
}
542+
}
543+
}
519544
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
520545
/* We're only interested in Joliet => make sure the SVD isn't overwritten */
521546
if (p_iso->u_joliet_level == 0)
@@ -1441,6 +1466,28 @@ iso9660_fs_stat_translate (CdIo_t *p_cdio, const char psz_path[])
14411466
iso9660_stat_t *
14421467
iso9660_ifs_stat_translate (iso9660_t *p_iso, const char psz_path[])
14431468
{
1469+
/* Special case for virtual El-Torito boot images ('[BOOT]/#.img') */
1470+
if (psz_path && (strncmp(psz_path, "[BOOT]/", 7) == 0)) {
1471+
int index = psz_path[7] - '0';
1472+
iso9660_stat_t* p_stat;
1473+
if (strlen(psz_path) < 8)
1474+
return NULL;
1475+
if ((psz_path[7] < '0') || (psz_path[7] > '0' + MAX_BOOT_IMAGES - 1))
1476+
return NULL;
1477+
if (p_iso->boot_img[index].lsn == 0 || p_iso->boot_img[index].num_sectors == 0)
1478+
return NULL;
1479+
p_stat = calloc(1, sizeof(iso9660_stat_t) + strlen(psz_path));
1480+
if (!p_stat) {
1481+
cdio_warn("Couldn't calloc(1, %d)", (int)sizeof(iso9660_stat_t));
1482+
return NULL;
1483+
}
1484+
p_stat->lsn = p_iso->boot_img[index].lsn;
1485+
p_stat->total_size = p_iso->boot_img[index].num_sectors * ISO_BLOCKSIZE;
1486+
p_stat->type = _STAT_FILE;
1487+
strcpy(p_stat->filename, psz_path);
1488+
return p_stat;
1489+
}
1490+
14441491
return fs_stat_translate(p_iso, (stat_root_t *) _ifs_stat_root,
14451492
(stat_traverse_t *) _fs_iso_stat_traverse,
14461493
psz_path);

src/rufus.rc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
3333
IDD_DIALOG DIALOGEX 12, 12, 232, 326
3434
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
3535
EXSTYLE WS_EX_ACCEPTFILES
36-
CAPTION "Rufus 4.4.2099"
36+
CAPTION "Rufus 4.4.2100"
3737
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
3838
BEGIN
3939
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@@ -392,8 +392,8 @@ END
392392
//
393393

394394
VS_VERSION_INFO VERSIONINFO
395-
FILEVERSION 4,4,2099,0
396-
PRODUCTVERSION 4,4,2099,0
395+
FILEVERSION 4,4,2100,0
396+
PRODUCTVERSION 4,4,2100,0
397397
FILEFLAGSMASK 0x3fL
398398
#ifdef _DEBUG
399399
FILEFLAGS 0x1L
@@ -411,13 +411,13 @@ BEGIN
411411
VALUE "Comments", "https://rufus.ie"
412412
VALUE "CompanyName", "Akeo Consulting"
413413
VALUE "FileDescription", "Rufus"
414-
VALUE "FileVersion", "4.4.2099"
414+
VALUE "FileVersion", "4.4.2100"
415415
VALUE "InternalName", "Rufus"
416416
VALUE "LegalCopyright", "� 2011-2024 Pete Batard (GPL v3)"
417417
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
418418
VALUE "OriginalFilename", "rufus-4.4.exe"
419419
VALUE "ProductName", "Rufus"
420-
VALUE "ProductVersion", "4.4.2099"
420+
VALUE "ProductVersion", "4.4.2100"
421421
END
422422
END
423423
BLOCK "VarFileInfo"

0 commit comments

Comments
 (0)