VISO: Overhaul El Torito boot code insertion, now following the 7-Zip syntax which allows for explicit type definition

This commit is contained in:
RichardG867
2022-10-16 01:59:13 -03:00
parent 5d79413064
commit 99617668ea

View File

@@ -106,13 +106,13 @@ typedef struct _viso_entry_ {
} viso_entry_t; } viso_entry_t;
typedef struct { typedef struct {
uint64_t vol_size_offsets[2], pt_meta_offsets[2], eltorito_offset; uint64_t vol_size_offsets[2], pt_meta_offsets[2];
int format; int format;
size_t metadata_sectors, all_sectors, entry_map_size, sector_size, file_fifo_pos; size_t metadata_sectors, all_sectors, entry_map_size, sector_size, file_fifo_pos;
uint8_t *metadata; uint8_t *metadata;
track_file_t tf; track_file_t tf;
viso_entry_t *root_dir, *eltorito_entry, **entry_map, *file_fifo[VISO_OPEN_FILES]; viso_entry_t *root_dir, **entry_map, *file_fifo[VISO_OPEN_FILES];
} viso_t; } viso_t;
static const char rr_eid[] = "RRIP_1991A"; /* identifiers used in ER field for Rock Ridge */ static const char rr_eid[] = "RRIP_1991A"; /* identifiers used in ER field for Rock Ridge */
@@ -745,10 +745,12 @@ viso_init(const char *dirname, int *error)
/* Set up directory traversal. */ /* Set up directory traversal. */
cdrom_image_viso_log("VISO: Traversing directories:\n"); cdrom_image_viso_log("VISO: Traversing directories:\n");
viso_entry_t *entry, *last_entry, *dir, *last_dir; viso_entry_t *entry, *last_entry, *dir, *last_dir, *eltorito_dir = NULL, *eltorito_entry = NULL;
struct dirent *readdir_entry; struct dirent *readdir_entry;
int len; int len, eltorito_others_present = 0;
size_t dir_path_len; size_t dir_path_len;
uint64_t eltorito_offset = 0;
uint8_t eltorito_type = 0;
/* Fill root directory entry. */ /* Fill root directory entry. */
dir_path_len = strlen(dirname); dir_path_len = strlen(dirname);
@@ -840,7 +842,7 @@ viso_init(const char *dirname, int *error)
memset(&entry->stats, 0x00, sizeof(struct stat)); memset(&entry->stats, 0x00, sizeof(struct stat));
} }
/* Handle file size. */ /* Handle file size and El Torito boot code. */
if (!S_ISDIR(entry->stats.st_mode)) { if (!S_ISDIR(entry->stats.st_mode)) {
/* Limit to 4 GB - 1 byte. */ /* Limit to 4 GB - 1 byte. */
if (entry->stats.st_size > ((uint32_t) -1)) if (entry->stats.st_size > ((uint32_t) -1))
@@ -850,11 +852,36 @@ viso_init(const char *dirname, int *error)
viso->entry_map_size += entry->stats.st_size / viso->sector_size; viso->entry_map_size += entry->stats.st_size / viso->sector_size;
if (entry->stats.st_size % viso->sector_size) if (entry->stats.st_size % viso->sector_size)
viso->entry_map_size++; /* round up to the next sector */ viso->entry_map_size++; /* round up to the next sector */
}
/* Detect El Torito boot code file and set it accordingly. */ /* Detect El Torito boot code file and set it accordingly. */
if ((dir == viso->root_dir) && !strnicmp(readdir_entry->d_name, "eltorito.", 9) && (!stricmp(readdir_entry->d_name + 9, "com") || !stricmp(readdir_entry->d_name + 9, "img"))) if (dir == eltorito_dir) {
viso->eltorito_entry = entry; if (!stricmp(readdir_entry->d_name, "Boot-NoEmul.img")) {
eltorito_type = 0x00;
have_eltorito_entry:
if (eltorito_entry)
eltorito_others_present = 1; /* flag that the boot code directory contains other files */
eltorito_entry = entry;
} else if (!stricmp(readdir_entry->d_name, "Boot-1.2M.img")) {
eltorito_type = 0x01;
goto have_eltorito_entry;
} else if (!stricmp(readdir_entry->d_name, "Boot-1.44M.img")) {
eltorito_type = 0x02;
goto have_eltorito_entry;
} else if (!stricmp(readdir_entry->d_name, "Boot-2.88M.img")) {
eltorito_type = 0x03;
goto have_eltorito_entry;
} else if (!stricmp(readdir_entry->d_name, "Boot-HardDisk.img")) {
eltorito_type = 0x04;
goto have_eltorito_entry;
} else {
eltorito_others_present = 1; /* flag that the boot code directory contains other files */
}
}
} else if ((dir == viso->root_dir) && !stricmp(readdir_entry->d_name, "[BOOT]")) {
/* Set this as the directory containing El Torito boot code. */
eltorito_dir = entry;
eltorito_others_present = 0;
}
/* Set short filename. */ /* Set short filename. */
if (viso_fill_fn_short(entry->name_short, entry, dir_entries)) { if (viso_fill_fn_short(entry->name_short, entry, dir_entries)) {
@@ -1008,8 +1035,8 @@ next_dir:
/* Write El Torito boot descriptor. This is an awkward spot for /* Write El Torito boot descriptor. This is an awkward spot for
that, but the spec requires it to be the second descriptor. */ that, but the spec requires it to be the second descriptor. */
if (!i && viso->eltorito_entry) { if (!i && eltorito_entry) {
cdrom_image_viso_log("VISO: Writing El Torito boot descriptor for entry [%08X]\n", viso->eltorito_entry); cdrom_image_viso_log("VISO: Writing El Torito boot descriptor for entry [%08X]\n", eltorito_entry);
p = data; p = data;
if (viso->format <= VISO_FORMAT_HSF) if (viso->format <= VISO_FORMAT_HSF)
@@ -1024,7 +1051,7 @@ next_dir:
VISO_SKIP(p, 40); VISO_SKIP(p, 40);
/* Save the boot catalog pointer's offset for later. */ /* Save the boot catalog pointer's offset for later. */
viso->eltorito_offset = ftello64(viso->tf.file) + (p - data); eltorito_offset = ftello64(viso->tf.file) + (p - data);
/* Blank the rest of the working sector. */ /* Blank the rest of the working sector. */
memset(p, 0x00, viso->sector_size - (p - data)); memset(p, 0x00, viso->sector_size - (p - data));
@@ -1059,10 +1086,10 @@ next_dir:
} }
/* Handle El Torito boot catalog. */ /* Handle El Torito boot catalog. */
if (viso->eltorito_entry) { if (eltorito_entry) {
/* Write a pointer to this boot catalog to the boot descriptor. */ /* Write a pointer to this boot catalog to the boot descriptor. */
*((uint32_t *) data) = cpu_to_le32(ftello64(viso->tf.file) / viso->sector_size); *((uint32_t *) data) = cpu_to_le32(ftello64(viso->tf.file) / viso->sector_size);
viso_pwrite(data, viso->eltorito_offset, 4, 1, viso->tf.file); viso_pwrite(data, eltorito_offset, 4, 1, viso->tf.file);
/* Fill boot catalog validation entry. */ /* Fill boot catalog validation entry. */
p = data; p = data;
@@ -1085,38 +1112,14 @@ next_dir:
/* Now fill the default boot entry. */ /* Now fill the default boot entry. */
*p++ = 0x88; /* bootable flag */ *p++ = 0x88; /* bootable flag */
*p++ = eltorito_type; /* boot media type */
if (viso->eltorito_entry->name_short[9] == 'C') { /* boot media type: non-emulation */
*p++ = 0x00;
} else { /* boot media type: emulation */
/* This could use with a decoupling of fdd_img's algorithms
for loading non-raw images and detecting raw image sizes. */
switch (viso->eltorito_entry->stats.st_size) {
case 0 ... 1228800: /* 1.2 MB */
*p++ = 0x01;
break;
case 1228801 ... 1474560: /* 1.44 MB */
*p++ = 0x02;
break;
case 1474561 ... 2949120: /* 2.88 MB */
*p++ = 0x03;
break;
default: /* hard drive */
*p++ = 0x04;
break;
}
}
*p++ = 0x00; /* load segment */ *p++ = 0x00; /* load segment */
*p++ = 0x00; *p++ = 0x00;
*p++ = 0x00; /* system type (is this even relevant?) */ *p++ = 0x00; /* system type (is this even relevant?) */
*p++ = 0x00; /* reserved */ *p++ = 0x00; /* reserved */
/* Save offsets to the boot catalog entry's offset and size fields for later. */ /* Save offsets to the boot catalog entry's offset and size fields for later. */
viso->eltorito_offset = ftello64(viso->tf.file) + (p - data); eltorito_offset = ftello64(viso->tf.file) + (p - data);
/* Blank the rest of the working sector. This includes the sector count, /* Blank the rest of the working sector. This includes the sector count,
ISO sector offset and 20-byte selection criteria fields at the end. */ ISO sector offset and 20-byte selection criteria fields at the end. */
@@ -1132,6 +1135,10 @@ next_dir:
memset(data, 0x00, write); memset(data, 0x00, write);
fwrite(data, write, 1, viso->tf.file); fwrite(data, write, 1, viso->tf.file);
} }
/* Flag that we shouldn't hide the boot code directory if it contains other files. */
if (eltorito_others_present)
eltorito_dir = NULL;
} }
/* Write each path table. */ /* Write each path table. */
@@ -1150,8 +1157,9 @@ next_dir:
dir = viso->root_dir; dir = viso->root_dir;
uint16_t pt_idx = 1; uint16_t pt_idx = 1;
while (dir) { while (dir) {
/* Ignore . and .. pseudo-directories. */ /* Ignore . and .. pseudo-directories, and hide the El Torito
if (dir->name_short[0] == '.' && (dir->name_short[1] == '\0' || (dir->name_short[1] == '.' && dir->name_short[2] == '\0'))) { boot code directory if no other files are present in it. */
if ((dir->name_short[0] == '.' && (dir->name_short[1] == '\0' || (dir->name_short[1] == '.' && dir->name_short[2] == '\0'))) || (dir == eltorito_dir)) {
dir = dir->next_dir; dir = dir->next_dir;
continue; continue;
} }
@@ -1228,6 +1236,12 @@ next_dir:
/* Go through directories. */ /* Go through directories. */
dir = viso->root_dir; dir = viso->root_dir;
while (dir) { while (dir) {
/* Hide the El Torito boot code directory if no other files are present in it. */
if (dir == eltorito_dir) {
dir = dir->next_dir;
continue;
}
/* Pad to the next sector if required. */ /* Pad to the next sector if required. */
write = ftello64(viso->tf.file) % viso->sector_size; write = ftello64(viso->tf.file) % viso->sector_size;
if (write) { if (write) {
@@ -1255,8 +1269,9 @@ next_dir:
/* Go through entries in this directory. */ /* Go through entries in this directory. */
entry = dir->first_child; entry = dir->first_child;
while (entry) { while (entry) {
/* Skip the El Torito boot code entry if present. */ /* Skip the El Torito boot code entry if present, or hide the
if (entry == viso->eltorito_entry) boot code directory if no other files are present in it. */
if ((entry == eltorito_entry) || (entry == eltorito_dir))
goto next_entry; goto next_entry;
cdrom_image_viso_log("[%08X] %s => %s\n", entry, dir->path, cdrom_image_viso_log("[%08X] %s => %s\n", entry, dir->path,
@@ -1386,10 +1401,10 @@ next_entry:
/* Write this file's base sector offset to its directory /* Write this file's base sector offset to its directory
entries, unless this is the El Torito boot code entry, entries, unless this is the El Torito boot code entry,
in which case, write offset and size to the boot entry. */ in which case, write offset and size to the boot entry. */
if (entry == viso->eltorito_entry) { if (entry == eltorito_entry) {
/* Load the entire file if not emulating, or just the first virtual /* Load the entire file if not emulating, or just the first virtual
sector (which usually contains all the boot code) if emulating. */ sector (which usually contains all the boot code) if emulating. */
if (entry->name_short[9] == 'C') { /* non-emulation */ if (eltorito_type == 0x00) { /* non-emulation */
uint32_t boot_size = entry->stats.st_size; uint32_t boot_size = entry->stats.st_size;
if (boot_size % 512) /* round up */ if (boot_size % 512) /* round up */
boot_size += 512 - (boot_size % 512); boot_size += 512 - (boot_size % 512);
@@ -1398,7 +1413,7 @@ next_entry:
*((uint16_t *) &data[0]) = cpu_to_le16(1); *((uint16_t *) &data[0]) = cpu_to_le16(1);
} }
*((uint32_t *) &data[2]) = cpu_to_le32(viso->all_sectors * base_factor); *((uint32_t *) &data[2]) = cpu_to_le32(viso->all_sectors * base_factor);
viso_pwrite(data, viso->eltorito_offset, 6, 1, viso->tf.file); viso_pwrite(data, eltorito_offset, 6, 1, viso->tf.file);
} else { } else {
p = data; p = data;
VISO_LBE_32(p, viso->all_sectors * base_factor); VISO_LBE_32(p, viso->all_sectors * base_factor);